一个灵巧的Delphi多播实现方案

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

一个灵巧的Delphi多播实现方案.必须是支持泛型的Delphi版本.也就是Delphi2009以后.强烈建议用DelphiXE.用法就是例如写一个Class指定一个Event,触发的时候会通知多个Method.和.NET的多播事件机制是一样的.用法例如:typeTFakeButton=class(TButton)privateFMultiCast_OnClik:TMulticastEventTNotifyEvent;publicconstructorCreate(AOwnder:TComponent);override;destructorDestroy;override;procedureClick;override;propertyMultiCast_OnClik:TMulticastEventTNotifyEventreadFMultiCast_OnClik;end;{TTest}procedureTFakeButton.Click;begininherited;//这样调用可以通知多个事件FMultiCast_OnClik.Invok(Self);end;constructorTFakeButton.Create(AOwnder:TComponent);begininheritedCreate(AOwnder);FMultiCast_OnClik:=TMulticastEventTNotifyEvent.Create;end;destructorTFakeButton.Destroy;beginFMultiCast_OnClik.Free;inheritedDestroy;end;//procedureTForm2.Button1Click(Sender:TObject);varTest:TFakeButton;beginTest:=TFakeButton.Create(Self);Test.MultiCast_OnClik.Add(TestA);Test.MultiCast_OnClik.Add(TestB);Test.SetBounds(0,0,100,100);test.Caption:='试试多播';Test.Parent:=Self;end;procedureTForm2.TestA(Sender:TObject);beginShowMessage(Caption);end;procedureTForm2.TestB(Sender:TObject);beginShowMessage(FormatDateTime('yyyy-mm-ddhh:nn:ss',now));end;在按钮上点一下,直接会触发TestA,和TestB.这个做法主要是省了写一个事件容器,然后循环调用的麻烦.下面是方案的代码:{一个多播方法的实现.和一位同事(一位Delphi牛人)一起讨论了一下Delphi下多播事件的实现.他提供了一个易博龙技术牛人的多播事件方案.这个方案非常牛,但是依赖Delphi的编译器特性太多,只能用在开启优化的代码.而DelphiXE默认Debug是关闭优化的.重写了一个TMulticastEvent.这个不依赖Delphi的编译器产生的代码特性.其中InternalInvoke基本上是那位易博龙大牛的代码.加了详细的注释wr960204.2011.5.28}unitMultiCastEventUtils;interfaceusesGenerics.collections,TypInfo,ObjAuto,SysUtils;type//TMulticastEvent=classprivateFMethods:TListTMethod;FInternalDispatcher:TMethod;//悲催的是泛型类的方法不能内嵌汇编,只能通过一个非泛型的父类来实现procedureInternalInvoke(Params:PParameters;StackSize:Integer);publicconstructorCreate;destructorDestroy;override;end;TMulticastEventT=class(TMulticastEvent)privateFEntry:T;functionConvertToMethod(varValue):TMethod;procedureSetEntry(varAEntry);publicconstructorCreate;destructorDestroy;override;procedureAdd(AMethod:T);procedureRemove(AMethod:T);functionIndexOf(AMethod:T):Integer;propertyInvok:TreadFEntry;end;implementation{TMulticastEventT}procedureTMulticastEventT.Add(AMethod:T);varm:TMethod;beginm:=ConvertToMethod(AMethod);ifFMethods.IndexOf(m)0thenFMethods.Add(m);end;functionTMulticastEventT.ConvertToMethod(varValue):TMethod;beginResult:=TMethod(Value);end;constructorTMulticastEventT.Create();varMethInfo:PTypeInfo;TypeData:PTypeData;beginMethInfo:=TypeInfo(T);ifMethInfo^.KindtkMethodthenbeginraiseException.Create('TonlyisMethod(Memberfunction)!');end;TypeData:=GetTypeData(MethInfo);Inherited;FInternalDispatcher:=CreateMethodPointer(InternalInvoke,TypeData);SetEntry(FEntry);end;destructorTMulticastEventT.Destroy;beginReleaseMethodPointer(FInternalDispatcher);inheritedDestroy;end;functionTMulticastEventT.IndexOf(AMethod:T):Integer;beginResult:=FMethods.IndexOf(ConvertToMethod(AMethod));end;procedureTMulticastEventT.Remove(AMethod:T);beginFMethods.Remove(ConvertToMethod(AMethod));end;procedureTMulticastEventT.SetEntry(varAEntry);beginTMethod(AEntry):=FInternalDispatcher;end;{TMulticastEvent}constructorTMulticastEvent.Create;beginFMethods:=TListTMethod.Create;end;destructorTMulticastEvent.Destroy;beginFMethods.Free;inheritedDestroy;end;procedureTMulticastEvent.InternalInvoke(Params:PParameters;StackSize:Integer);varLMethod:TMethod;beginforLMethodinFMethodsdobegin//如果用到了栈(也就是Register约定参数大于2或者stdcall,cdecl约定)就把栈内所有数据都拷贝参数栈里面ifStackSize0thenasmMOVECX,StackSize//Move的第三个参数,同时为下一步SubESP做准备SUBESP,ECX//把栈顶-StackSize(栈是负向的)MOVEDX,ESP//Move的第二个参数MOVEAX,ParamsLEAEAX,[EAX].TParameters.Stack[8]//Move的第一个参数CALLSystem.Moveend;//Register协议填写三个寄存器,EAX肯定是Self,如果是其他协议寄存器被填写也没啥影响asmMOVEAX,Params//把Params读到EAXMOVEDX,[EAX].TParameters.Registers.DWORD[0]//EDXMOVECX,[EAX].TParameters.Registers.DWORD[4]//EAXMOVEAX,LMethod.Data//把Method.Data给到EAX,如果是Register约定就是Self.否则也没影响CALLLMethod.Code//调用Method.Dataend;end;end;end.本文来自CSDN博客,转载请标明出处:比如你在动态创建的时候加上btns[I].tag:=i;Sender就能判断ifTButton(Sender).tag=0then就说点击是你动态创建的按钮里面的第一个按钮:你的意思是把多个按钮的click事件指向一个事件处理过程,然后再判断到底是按下那个按钮吗?2:if(Sender=Button1)thenShowMessage('button1被按下了.');3:在Click事件里写如下:ShowMessage(TButton(Sender).Name);//显示Button的名字4:桦树皮说的对,就是这个意思5:下面的是image的事件,button是一样的unitUnit1;interfaceusesWindows,Messages,SysUtils,Classes,Graphics,Controls,Forms,Dialogs,ExtCtrls;typeTForm1=class(TForm)procedureFormCreate(Sender:TObject);private{Privatedeclarations}publicproceduremyImageArrayClick(Sender:TObject);end;constn=10;varForm1:TForm1;myimage:array[0..n]ofTImage;implementation{$R*.DFM}procedureTForm1.myImageArrayClick(Sender:TObject);beginTImage(Sender).Picture.loadFromFile('2.bmp');//这里可以改成ShowMessage(IntToStr(TButton(Sender).Tag));end;procedureTForm1.FormCreate(Sender:TObject);vari,j:Integer;beginfori:=0tondoforj:=0tondobeginmyimage[i*nj]:=TImage.Create(self);myimage[i*nj].Parent:=Form1;myimage[i*nj].SetBounds(j*48,i*48,48,48);myimage[i*nj].OnClick:=myImageArrayClick;//myimage[i*nj].Picture.LoadFromFile('1.bmp');//这里该为

1 / 10
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功