遇到个难题,请大家帮忙想点子:怎么在一个未知类型的事件之后执行一段指定的代码(300)

  • 主题发起人 主题发起人 ActFish
  • 开始时间 开始时间
A

ActFish

Unregistered / Unconfirmed
GUEST, unregistred user!
问题描述:比如窗体上有个Button1,DataSource1...,他们的事件如下:procedure TForm1.Button1Click(Sender: TObject);begin ShowMessage('Button1的onclick事件');end;procedure TForm1.DataSource1DataChange(Sender: TObject; Field: TField);begin ShowMessage('DataSource1的OnDataChange事件');end;而我还有个特殊的过程(或者普通过程也可以)是:procedure TForm1.MyProc(Sender: TObject;EveName:string);begin ShowMessage('执行了'+TComponent(Sender).name+'的'+EveName+事件');end;我的意思是在能够自动在Button1点击、DataSource1的OnDataChange之后,能够自动执行MyProc这个过程;请不要说在代码中写,因为我事先并不知道都哪些事件、什么类型(比如TNotifyEvent)的事件会自动执行这个过程,不知道我描述清楚没有?
 
这个问题本质就是:要可以定义指定事件中执行一个通用的过程,定义的地方我可以定义那些控件的那些事件去执行这个过程
 
你这样的设想可能太复杂了,把你的需求写出来,看看有没有其它的替代方法。
 
看看delphi是如何调用Click事件、OnDataChange事件的,你就知道,不在代码中写,没法实现这样的功能。
 
说白了,这个也是为了权限控制用的,我事前并不知道都哪些事件需要权限控制,也不知道事件的类型,至于哪些事件发生时候要检查权限,我可以做个功能,指定哪个控件的哪个事件需要权限控制,那么当这个事件执行前或执行后,我要可以让自动执行权限检查或控制的代码,这个就是我的需求,如果只是特定类型的事件才检查,这个容易做出来,但关键是不知道事件类型不知道清楚我的需求没?谢谢
 
说明一点,这个通用的过程,可以接受起码2个参数,发生事件的控件(或控件名)、发生的事件名
 
function aaa(Params: array of pointer): pointer;
 
问一下,假设你已经实现了,那么你在权限管理中也需要配置操作员对每个界面所拥有的权限的吧?是不是在那里,你需要自动生成出来每个界面有哪些事件?也许你能看明白那些英文信息的事件,但管理员可以看懂吗?况且,你怎么生成每个界面拥有哪些事件呢?个人觉得,通过这种方式来实现,难度很大。当然,如果你实现了,那对项目组中其他程序员来说,省了不少力。补充一下,如果软件中用到的控件全部是自己在原先Delphi上扩展的,那实现起来就很容易了。
 
现在是是可以做到配置了,现在就差这个关键地方了,这个打通了就可以了
 
白河愁的function aaa(Params: array of pointer): pointer; 有点启发,先实验下是否能行得通,大家继续
 
1>你应该可以整理出来整套系统大概需要处理哪些事件,例如按钮的Click,DataSet的OnDataChange(TDataChangeEvent)等等,估计类型不会很多,在Controls单元的566行,你也可以看到控件的事件也就是那么些,再加上一些非可视化控件的事件。2>针对这些类型的事件,你在一个BaseForm中,分别定义上相应的过程; 增加一个结构体,如下 _CompEvent=Record Comp:TComponent; EventName:String; EventPoint:Pointer; End; ArrCompEvent:Array of _CompEvent; 窗体中定义一个ArrCompEvent类型的变量,如FCompEvent3>Form.Create中,循环遍历所有Components,查看Component是否定义了事件,如果定义了,则将该信息添加到FCompEvent元素中, 并将该Component对应的事件更改为我们步骤2中定义的相应的过程4>在步骤2中的所有定义过程中,分别都调用你的MyProc过程,下面就是如何执行原先的函数了,我们有ArrCompEvent数组,应该可以根据当前Sender的Name和当前事件的类型,找到原先的EventPoint,并执行原程序员写的函数。5>需要注意的是,对应Edit的KeyDown和KeyUp,函数类型是一样的,因此_CompEvent中还需要EventName属性。6》所有界面都从BaseForm继承。
 
非常感谢znxia,你的思路很好,能行的通,我现在还是想知道怎么在不知道事件类型的情况下怎么处理,关键也是这里;白河愁 Params: array of pointer这个有点启发,也非常感谢。
 
我找到了一个方法可以解决参数传递问题,白河愁的启发的: function E1(s1:PInteger=nil;s2:PInteger=nil;s3:PInteger=nil;s4:PInteger=nil):PInteger;PInteger可以接受任何类型的参数,多几个参数就可以了,如下的测试代码通过,但请大家看看有没有更好的方案:var Form1: TForm1; Pold:Pointer; aFun:TFun; function E1(s1:PInteger=nil;s2:PInteger=nil;s3:PInteger=nil;s4:PInteger=nil):PInteger;implementation{$R *.dfm}function E1(s1:PInteger=nil;s2:PInteger=nil;s3:PInteger=nil;s4:PInteger=nil):PInteger;var LP:PInteger; P:Pointer;begin Application.MessageBox('执行了E1过程,对象名是','提示',MB_OK); LP := @TMethod(Form1.Edit1.OnKeyDown); LP^ := Integer(Pold); @aFun:=@Form1.Edit1.OnKeyDown; if Assigned(aFun) then aFun(s1,s2,s3,s4); //下面再还原加载事件上去,便于下次执行 Pold:= Addr(Form1.Edit1.OnKeyDown);//保存Edit1.OnKeyDown到P P:= Addr(e1); LP := @TMethod(Form1.Edit1.OnKeyDown);//把事件地址给中间指针变量 LP^ := Integer(P);//回复以前保存的指针到中间指针变量(就是事件,地址是相同的) //8Abort;end;procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);begin Application.MessageBox(PChar(TControl (Sender).Name),pchar(inttostr(Key)),MB_OK);end;procedure TForm1.Button1Click(Sender: TObject);var P:Pointer; LP:PInteger;begin Pold:= Addr(Edit1.OnKeyDown);//保存BEdit1.OnKeyDown到P P:= Addr(e1); LP := @TMethod(Edit1.OnKeyDown);//把事件地址给中间指针变量 LP^ := Integer(P);//回复以前保存的指针到中间指针变量(就是事件,地址是相同的)end;
 
1>你不知道界面上有多少控件写了事件,现在的测试代码Button1Click中是固定的,不符合你的初衷。2>函数E1中如何调用原程序员编写的代码没实现,现在是写死的3>另外写了一个Edit1KeyPress事件,调用E1函数完成后,异常。代码如下:function E1(s1: PInteger = nil; s2: PInteger = nil; s3: PInteger = nil; s4: PInteger = nil): PInteger;var LP: PInteger; P: Pointer;begin Application.MessageBox('执行了E1过程,对象名是', '提示', MB_OK); LP := @TMethod(Form1.Edit1.OnKeyPress); LP^ := Integer(Pold); @aFun := @Form1.Edit1.OnKeyPress; if Assigned(aFun) then aFun(s1, s2, s3, s4); //下面再还原加载事件上去,便于下次执行 Pold := Addr(Form1.Edit1.OnKeyPress); //保存Edit1.OnKeyDown到P P := Addr(e1); LP := @TMethod(Form1.Edit1.OnKeyPress); //把事件地址给中间指针变量 LP^ := Integer(P); //回复以前保存的指针到中间指针变量(就是事件,地址是相同的) //8Abort;end;procedure TForm1.Button1Click(Sender: TObject);var P: Pointer; LP: PInteger;begin Pold := Addr(Edit1.OnKeyPress); //保存BEdit1.OnKeyDown到P P := Addr(E1); LP := @TMethod(Edit1.OnKeyPress); //把事件地址给中间指针变量 LP^ := Integer(P); //回复以前保存的指针到中间指针变量(就是事件,地址是相同的)end;procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);begin if Key in ['0'..'9'] then Key:=#0;end;
 
我没有说清楚,上面的例子是仅仅是未知事件类型的参数传递问题,到正式程序中我会修改为可以用到窗体所有控件的任何事件,思路有点类似你上面:来自:znxia, 时间:2009-4-9 14:53:37, ID:3953075这个思路,报错好象有个事件我也测试到出错了, 这个错误,可以通过把 Abort加在后面解决,现在还有个问题就是不知道不知道传过来的事件的名,估计这个可以通过地址或地址偏移得到,我今天搞搞这个东西看是否有结果。大家有好的想法继续,谢谢大家!
 
我那个可以接受无限个参数,不存在这些限制。你只要用第一个参数来指定有多少个参数就行了。
 
白河愁:参数怎么接收?
 
你是可以接收无限个参数,但有没有考虑有的参数是传址参数?-----------------加Abort?如果我写的是OnBeforePost,那就惨了。
 
重写winproc试试,再sendmessage....
 
这个我已经写好了,写成了个组件,不用Abort了,有时间回头给大家看下,znxia,你的QQ多少?我还有很多好的想法讨论下
 
后退
顶部