当前位置: 首页 > news >正文

Delphi 利用接口实现frame窗体间的通讯(互动)

需求说明:

image

 程序设计:

image

效果演示:

test

设计思路:

f9dfe0ffbfd092f0f7bbace85f7c1ddb

 FrmCK 只负责发布事件,不关心谁在监听.

FrmGrid 只负责响应事件,不关心事件来源.

创建过程:

一.创建接口单元FrmInterface.

image

 全部代码如下:

unit FrmInterface;interfaceusessystem.SysUtils;type// 监听者接口IWarehouseSelectionListener = interface['{C2228C39-FA0D-448D-B905-43CD35C6EC0A}']procedure OnWarehouseSelected(const AWarehouseID: Integer; const AWarehouseCode: string);end;// 发布者接口IWarehouseSelectionPublisher = interface['{F2A92608-BDB0-4324-9FAA-539D4E237555}']procedure RegisterListener(AListener: IWarehouseSelectionListener);procedure UnregisterListener(AListener: IWarehouseSelectionListener);procedure NotifyWarehouseSelection(AWarehouseID: Integer; const AWarehouseCode: string);end;// 实现发布者接口的类TWarehouseSelectionPublisher = class(TInterfacedObject, IWarehouseSelectionPublisher)privateFListeners: TArray<IWarehouseSelectionListener>;publicprocedure RegisterListener(AListener: IWarehouseSelectionListener);procedure UnregisterListener(AListener: IWarehouseSelectionListener);procedure NotifyWarehouseSelection(AWarehouseID: Integer; const AWarehouseCode: string);destructor Destroy; override;end;// 全局发布者实例函数
function WarehousePublisher: IWarehouseSelectionPublisher;implementationvarFGlobalPublisher: IWarehouseSelectionPublisher;function WarehousePublisher: IWarehouseSelectionPublisher;
beginif not Assigned(FGlobalPublisher) thenFGlobalPublisher := TWarehouseSelectionPublisher.Create;Result := FGlobalPublisher;
end;{ TWarehouseSelectionPublisher }procedure TWarehouseSelectionPublisher.RegisterListener(AListener: IWarehouseSelectionListener);
begin// 检查是否已经注册for var i := 0 to High(FListeners) doif FListeners[i] = AListener thenExit;// 注册监听器SetLength(FListeners, Length(FListeners) + 1);FListeners[High(FListeners)] := AListener;
end;//
procedure TWarehouseSelectionPublisher.UnregisterListener(AListener: IWarehouseSelectionListener);
beginfor var i := 0 to High(FListeners) dobeginif FListeners[i] = AListener thenbegin// 移除监听器for var j := i to High(FListeners) - 1 doFListeners[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) dobegintryFListeners[i].OnWarehouseSelected(AWarehouseID, AWarehouseCode);excepton E: Exception do// 记录异常,但不中断其他监听器的通知
//        showmessage(PChar('通知监听器时发生错误: ' + E.Message));end;end;
end;destructor TWarehouseSelectionPublisher.Destroy;
beginSetLength(FListeners, 0);inherited;
end;initializationFGlobalPublisher := nil;finalizationFGlobalPublisher := nil;end.

 

二.发布者单元FrmCK

use
...,FrmInterface;  //引入接口单元typeTCK = 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);
begininherited;// 使用全局发布者实例FPublisher := WarehousePublisher;
end;destructor TCK.Destroy;
beginFPublisher := nil;inherited;
end;procedure TCK.cxDBTreeList1FocusedNodeChanged(Sender: TcxCustomTreeList;APrevFocusedNode, AFocusedNode: TcxTreeListNode);
varWarehouseID: Integer;WarehouseCode: string;
begin// 当 TreeList 节点改变时,通知所有监听器if not Assigned(AFocusedNode) then Exit;WarehouseID := GetSelectedWarehouseID;WarehouseCode := GetSelectedWarehouseCode;if (WarehouseID > 0) and (WarehouseCode <> '') thenbegin// 通过发布者通知所有监听器
    FPublisher.NotifyWarehouseSelection(WarehouseID, WarehouseCode);end;
end;function TCK.GetSelectedWarehouseCode: string;     //获取仓库代码,参数按实际需求设置
beginResult := '';if Assigned(cxDBTreeList1.FocusedNode) thenResult := cxDBTreeList1.FocusedNode.Values[1];
end;function TCK.GetSelectedWarehouseID: Integer;    //获取仓库ID,参数按实际需求设置
beginResult := -1;if Assigned(cxDBTreeList1.FocusedNode) thenResult := cxDBTreeList1.FocusedNode.Values[0];
end;
procedure TCK.RegisterListener(AListener: IWarehouseSelectionListener);
beginFPublisher.RegisterListener(AListener);
end;procedure TCK.UnregisterListener(AListener: IWarehouseSelectionListener);
beginFPublisher.UnregisterListener(AListener);
end;procedure TCK.NotifyWarehouseSelection(AWarehouseID: Integer;const AWarehouseCode: string);
beginFPublisher.NotifyWarehouseSelection(AWarehouseID, AWarehouseCode);
end;end.

三.监听者FrmGrid

unit FrmGrid;interfaceuses..., FrmInterface;typeTGrid = class(TFrame, IWarehouseSelectionListener)...private{ Private declarations }FListener: IWarehouseSelectionListener;constisql = 'SELECT 物料信息.ID AS 物料ID, 物料信息.物料代码, 物料信息.材质, 物料信息.物料名称, 物料信息.助记码, 物料信息.客户料号, 物料信息.规格型号, 物料信息.单位 AS 单位ID, 单位列表.单位名称, 物料信息.储位, 物料信息.单重, 物料信息.默认仓库 AS 仓库ID, 仓库列表.仓库名称 AS 默认仓库, 物料信息.启用状态, 物料信息.备注' + ' FROM 仓库列表 RIGHT JOIN (单位列表 RIGHT JOIN 物料信息 ON 单位列表.单位ID = 物料信息.单位) ON 仓库列表.仓库ID = 物料信息.默认仓库';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);
begininherited;// 将自己注册为监听器FListener := Self;WarehousePublisher.RegisterListener(FListener);
end;destructor TGrid.Destroy;
begin// 注销监听器if Assigned(FListener) thenWarehousePublisher.UnregisterListener(FListener);FListener := nil;inherited;
end;procedure TGrid.FinalizeFrame;
begin// 清理资源if Assigned(FListener) thenWarehousePublisher.UnregisterListener(FListener);
end;{ TGrid }// 当仓库选择时,加载对应仓库的物料数据
procedure TGrid.OnWarehouseSelected(const AWarehouseID: Integer; const AWarehouseCode: string);
beginwith DataModule1.FDQuery2 dobeginClose;if AWarehouseID = 1 then   //用户点到了'全部' 节点beginsql.Text := isql;endelsebeginvar isql2 := Format(isql + ' where 物料信息.默认仓库=%d', [AWarehouseID]);sql.Text := isql2;end;Open();end;end;end.

 

http://www.jsqmd.com/news/24963/

相关文章:

  • NRF54LM20A 芯片的优点
  • 零散点小总结(25.10.28)
  • Top Tree大学习
  • 乱学点东西目录
  • CFS任务的负载均衡(load balance)
  • EVE-NG导入华为等镜像的方法
  • (简记)一类支配点对解决区间查询问题
  • 2025 云斗
  • c++ ranges随笔
  • qoj14458. 调色滤镜
  • 第8天(中等题 不定长滑动窗口、哈希表)
  • P10259 [COCI 2023/2024 #5] Piratski kod
  • 巧用 using 作用域(IDisposable)的生命周期包装特性 实现前后置处理
  • 2025.10.27训练记录
  • 软考复习总结
  • ? #6
  • 鲜花:不会说明你有抑郁症3
  • 算法竞赛知识点速通手册
  • ROS1 go2 vlp16 局部避障--3 篇 - 教程
  • 25.10.28随笔NOIP模拟赛总结
  • 第二十八篇
  • P8269 [USACO22OPEN] Visits S
  • Luogu P13925 [POKATT 2024] 联合猫国 / The Paw-litical Game 题解 [ 蓝 ] [ 线性 DP ] [ 种类数观察 ]
  • 深入解析:【STM32项目开源】基于STM32的独居老人监护系统
  • CSP-S 41多校 9
  • 【25.10.28】模拟赛
  • CSP-S模拟41
  • Linux双中文编码笔记
  • C++类和对象(1) - 详解
  • 人工智能之编程基础 Python 入门:第二章 Python 的编辑器 VS Code