Delphi 利用接口实现frame窗体间的通讯(互动)
需求说明:

程序设计:

效果演示:

设计思路:

FrmCK 只负责发布事件,不关心谁在监听.
FrmGrid 只负责响应事件,不关心事件来源.
创建过程:
一.创建接口单元FrmInterface.然后在单元中需要声明两个接口,即监听事件的接口和发布事件的接口

  1.监听接口只需要声明一个过程即可,它接收发布事件传过来的参数(如果有的话) 
2.发布接口需要声明注册和销毁过程,参数是一个监听器.此外还要有一个广播过程,把需要的参数传播给监听接口
 全部代码如下:
unit FrmInterface; interface uses system.SysUtils; type // 监听器接口 - 用于接收仓库选择事件的组件需要实现此接口 IWarehouseSelectionListener = interface ['{C2228C39-FA0D-448D-B905-43CD35C6EC0A}'] // GUID,用于接口标识 // 当仓库被选择时调用的方法 procedure OnWarehouseSelected(const AWarehouseID: Integer; const AWarehouseCode: string); end; // 发布者接口 - 负责管理监听器并发布仓库选择事件 IWarehouseSelectionPublisher = interface ['{F2A92608-BDB0-4324-9FAA-539D4E237555}'] // GUID,用于接口标识 // 注册监听器 procedure RegisterListener(AListener: IWarehouseSelectionListener); // 取消注册监听器 procedure UnregisterListener(AListener: IWarehouseSelectionListener); // 通知所有监听器仓库选择事件 procedure NotifyWarehouseSelection(AWarehouseID: Integer; const AWarehouseCode: string); end; // 实现发布者接口的类 - 具体的事件发布者实现 TWarehouseSelectionPublisher = class(TInterfacedObject, IWarehouseSelectionPublisher) private FListeners: TArray<IWarehouseSelectionListener>; // 存储所有注册的监听器 public // 实现接口方法 procedure RegisterListener(AListener: IWarehouseSelectionListener); procedure UnregisterListener(AListener: IWarehouseSelectionListener); procedure NotifyWarehouseSelection(AWarehouseID: Integer; const AWarehouseCode: string); destructor Destroy; override; // 析构函数,清理资源 end; // 全局发布者实例函数 - 提供单例访问点 function WarehousePublisher: IWarehouseSelectionPublisher; implementation var FGlobalPublisher: IWarehouseSelectionPublisher; // 全局唯一的发布者实例 // 获取全局发布者实例的函数 function WarehousePublisher: IWarehouseSelectionPublisher; begin // 如果全局发布者尚未创建,则创建新实例 if not Assigned(FGlobalPublisher) then FGlobalPublisher := TWarehouseSelectionPublisher.Create; Result := FGlobalPublisher; // 返回全局发布者实例 end; { TWarehouseSelectionPublisher } // 注册监听器方法 procedure TWarehouseSelectionPublisher.RegisterListener(AListener: IWarehouseSelectionListener); begin // 检查监听器是否已经注册,避免重复注册 for var i := 0 to High(FListeners) do if FListeners[i] = AListener then Exit; // 如果已存在,直接退出 // 将监听器添加到监听器数组中 SetLength(FListeners, Length(FListeners) + 1); // 扩展数组长度 FListeners[High(FListeners)] := AListener; // 将新监听器放在数组末尾 end; // 取消注册监听器方法 procedure TWarehouseSelectionPublisher.UnregisterListener(AListener: IWarehouseSelectionListener); begin // 遍历所有监听器,查找要移除的监听器 for var i := 0 to High(FListeners) do begin if FListeners[i] = AListener then begin // 找到要移除的监听器,通过数组移位来移除 for var j := i to High(FListeners) - 1 do FListeners[j] := FListeners[j + 1]; // 将后续元素前移 SetLength(FListeners, Length(FListeners) - 1); // 缩减数组长度 Break; // 找到并移除后立即退出循环 end; end; end; // 通知所有监听器仓库选择事件 procedure TWarehouseSelectionPublisher.NotifyWarehouseSelection(AWarehouseID: Integer; const AWarehouseCode: string); begin // 遍历所有注册的监听器,逐一通知 for var i := 0 to High(FListeners) do begin try // 调用监听器的仓库选择处理方法 FListeners[i].OnWarehouseSelected(AWarehouseID, AWarehouseCode); except on E: Exception do // 捕获并处理异常,确保一个监听器的异常不会影响其他监听器的通知 // 这里可以记录日志,但保持注释状态以避免干扰用户界面 // showmessage(PChar('通知监听器时发生错误: ' + E.Message)); end; end; end; // 析构函数 destructor TWarehouseSelectionPublisher.Destroy; begin // 清理监听器数组,释放资源 SetLength(FListeners, 0); // 将数组长度设为0,释放内存 inherited; // 调用父类析构函数 end; initialization // 单元初始化部分,确保全局发布者初始为nil FGlobalPublisher := nil; finalization // 单元结束部分,清理全局发布者实例 FGlobalPublisher := nil; // 释放全局发布者引用 end.
二.发布者单元FrmCK
use ...,FrmInterface; //引入接口单元 type TCK = class(TFrame, IWarehouseSelectionPublisher) //调用发布者接口 ... procedure cxDBTreeList1FocusedNodeChanged(Sender: TcxCustomTreeList; APrevFocusedNode, AFocusedNode: TcxTreeListNode); //节点事件,触发发布者的广播行为 private { Private declarations } FPublisher: IWarehouseSelectionPublisher; function GetSelectedWarehouseID: Integer; function GetSelectedWarehouseCode: string;public { Public declarations } constructor Create(AOwner: TComponent); override; destructor Destroy; override; // IWarehouseSelectionPublisher 接口实现 procedure RegisterListener(AListener: IWarehouseSelectionListener); procedure UnregisterListener(AListener: IWarehouseSelectionListener); procedure NotifyWarehouseSelection(AWarehouseID: Integer; const AWarehouseCode: string); end; //主要代码 constructor TCK.Create(AOwner: TComponent); begin inherited; // 使用全局发布者实例 FPublisher := WarehousePublisher; end; destructor TCK.Destroy; begin FPublisher := nil; inherited; end; procedure TCK.cxDBTreeList1FocusedNodeChanged(Sender: TcxCustomTreeList; APrevFocusedNode, AFocusedNode: TcxTreeListNode); var WarehouseID: Integer; WarehouseCode: string; begin // 当 TreeList 节点改变时,通知所有监听器 if not Assigned(AFocusedNode) then Exit; WarehouseID := GetSelectedWarehouseID; WarehouseCode := GetSelectedWarehouseCode; if (WarehouseID > 0) and (WarehouseCode <> '') then begin // 通过发布者通知所有监听器 FPublisher.NotifyWarehouseSelection(WarehouseID, WarehouseCode); end; end; function TCK.GetSelectedWarehouseCode: string; //获取仓库代码,参数按实际需求设置 begin Result := ''; if Assigned(cxDBTreeList1.FocusedNode) then Result := cxDBTreeList1.FocusedNode.Values[1]; end; function TCK.GetSelectedWarehouseID: Integer; //获取仓库ID,参数按实际需求设置 begin Result := -1; if Assigned(cxDBTreeList1.FocusedNode) then Result := cxDBTreeList1.FocusedNode.Values[0]; end; procedure TCK.RegisterListener(AListener: IWarehouseSelectionListener); begin FPublisher.RegisterListener(AListener); end; procedure TCK.UnregisterListener(AListener: IWarehouseSelectionListener); begin FPublisher.UnregisterListener(AListener); end; procedure TCK.NotifyWarehouseSelection(AWarehouseID: Integer; const AWarehouseCode: string); begin FPublisher.NotifyWarehouseSelection(AWarehouseID, AWarehouseCode); end;end.
三.监听者FrmGrid
unit FrmGrid; interface uses ..., FrmInterface; type TGrid = class(TFrame, IWarehouseSelectionListener) ... private { Private declarations } FListener: IWarehouseSelectionListener; const isql = 'SELECT * from tblName'; public { Public declarations } constructor Create(AOwner: TComponent); override; destructor Destroy; override; // IWarehouseSelectionListener 接口实现 procedure OnWarehouseSelected(const AWarehouseID: Integer; const AWarehouseCode: string); procedure FinalizeFrame; end; implementation {$R *.dfm} constructor TGrid.Create(AOwner: TComponent); begin inherited; // 将自己注册为监听器 FListener := Self; WarehousePublisher.RegisterListener(FListener); end; destructor TGrid.Destroy; begin // 注销监听器 if Assigned(FListener) then WarehousePublisher.UnregisterListener(FListener); FListener := nil; inherited; end; procedure TGrid.FinalizeFrame; begin // 清理资源 if Assigned(FListener) then WarehousePublisher.UnregisterListener(FListener); end; { TGrid } // 当仓库选择时,加载对应仓库的物料数据 procedure TGrid.OnWarehouseSelected(const AWarehouseID: Integer; const AWarehouseCode: string); begin with DataModule1.FDQuery2 do begin Close; if AWarehouseID = 1 then //用户点到了'全部' 节点 begin sql.Text := isql; end else begin var isql2 := Format(isql + ' where 物料信息.默认仓库=%d', [AWarehouseID]); sql.Text := isql2; end; Open(); end; end; end.
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号