绝对没有办法把普通的procedure赋给一个类实例的事件指针吗? 解决的话,再加300分。(50分)

  • 主题发起人 主题发起人 shangshang
  • 开始时间 开始时间
S

shangshang

Unregistered / Unconfirmed
GUEST, unregistred user!
比如,我一个普通的全局过程Gproc。
想给一个动态创建的按钮赋onclick,
我非常想类似这样
onclick:=Gproc;
可是当然不行,因为类型不同,它们各自的空间大小也不同,普通的proc没有类指针。不能
给Tnotifyevent类型赋值。我知道一个类方法可以做到。但我现在的目的想让它执行Gproc
的代码,在不另创建任何类实例的情况下,如何调用呢。

如果可以实现,我可以再加300分。呵呵
 
直接像你上面这样onclick := Gproc;肯定不行,原因如你所说!
但对于onclick这种过程指针类型,就我所知好像只能赋于同它兼容的过程指针类型,而如
你所述很想直接利用Gproc这个普通全局过程,所以,只好这样做了:
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
private
procedure MyOnClick(Sender : TObject);
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure Gproc;
begin
//你的代码
end;

{ TForm1 }

procedure TForm1.MyOnClick(Sender: TObject);
begin
Gproc;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
Button2.OnClick := MyOnClick;
end;
[8D]我只能想到这一层,期盼更好的解决方案!
 
可以,只要他们穿入的参数类型一样就可以了,
 
1.Forms单元中有一个MakeObjectInstance过程,通过一个巧妙的方法在普通过程与类方法
之间转换,你可参考看看。
2.使用class procedure,不需要创建类实例:
type
TMyClass = class
class procedure Gproc(Sender: Object);
end;
然后可以赋值 Button1.OnClick := TMyClass.Gproc;
 
3.通过分析Classes单元,一番摸索终于找到一个方法,使用RTTI来解决:
implementation

uses
TypInfo;

// 类方法隐藏了第一个参数为对象的 Self (放在EAX中传递)
// 故第一个参数为 Self: TObject
// 第二个参数对应 TNotifyEvent 的参数
procedure Gproc(Self: TObject; Sender: TObject);
begin
ShowMessage('Test');
end;

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
var
M: TMethod; // 方法记录
begin
M.Code := @Gproc; // 指向方法(这里是全局过程)地址
M.Data := nil; // 指向类实例(该值对应着 Gproc 调用时的 Self 参数值,可为任意值,这里传nil)
SetMethodProp(Button1, 'OnClick', M); // 调用 RTTI 过程,动态设置事件
end;

试试看:)
 
补充,也可不用 SetMothodProp ,直接用
Button1.OnClick := TNotifyEvent(M);
来代替,这样uses TypInfo;也可以省了。
 
这是一个有价值的讨论,现在dfw这样的好问题不多了,收藏。
 
没有必要这么麻烦把,只要参数的类型一致,就可以进行普通的procedure赋给一个类实例的事件指针
 
请张兄具体给出一个例子,好让大家学习一下!
 
TO Archerfl:
我写了一个界面类似QQ的控件,就是用的和你一样的办法,只要procedure参数一样,
就可以进行事件赋值。
 
答案基本差不多了,如果你想深入的话,我先说个大概:
创建动态控件的winproc,当收到click之类的消息时,执行你那个全局过程;
 
原理就是自己处理消息循环而已
 
张无忌说的没错,
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TDoIt=procedure(arg1:integer;arg2:string);
TForm1 = class(TForm)
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
FDoIt: TDoIt;
public
procedure DoIt;
property OnDoIt:TDoIt read FDoIt write FDoIt;
end;
procedure doIt1(arg1:integer;arg2:string);
var
Form1: TForm1;

implementation

procedure doIt1(arg1:integer;arg2:string);
begin
ShowMessage(inttostr(arg1)+arg2);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
form1.OnDoIt:=@doit1;
end;

procedure TForm1.DoIt;
begin
if Assigned(FDoIt) then
FDoIt(1,'hello');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
DoIt;
end;

end.
 
》》1.Forms单元中有一个MakeObjectInstance过程,通过一个巧妙的方法在普通过程与类方法之间转换

我只用过MakeObjectInstance把类的方法(不是类方法)转化成普通过程,没有做过相反的过程,
yygw:请举个例子好吗? 另外你用RTTI来解决给了我很大的启发,谢谢:)
 
用ActionList不知可以吗?
 
to SaveNight:
问题的意思好象不是这样,是已知TNotify类型了,要把一个过程指针送去,比如OnCreate时发生。
象你这样自己定义数据类型,当然是很容易罗,而且你的参数又不是指针,根本上跟要求不一样嘛。
我问你了,我想调用
procedure myproc(Sender: TObject);
时,Sender就是调用的那个类,好象不是那么容易解决哦。
Button1.OnClick := @myproc;
当调用时,Sender 是个nil。
yygw说得挺有道理的,但没时间试 :)
 
不好意思,我一直没有时间仔细实验。
问题可以说已经解决,我会再开个帖子给300分。
yygw的方法完全没有问题,并且和我的理解一样,但提供了解决。可以说正是我想要的。
还有张无及和savenight的方法也不错,但我不明白道理在哪里,还有如何实现,恕我愚钝。
能再多叙述些吗?我很希望这是一个更好更安全的方法。谢谢
 
另:
如szf所说,savenight所举的栗子,等于是字定义的过程指针鳆值后,以事件的方式进行调用
这种方式跟我的初中相差很大, 我想得到的是一个事件类型指针,这种方法并没有实现。
张无及说的自己处理消息循环到底又是什么方式实现呢?
相信大家跟我一样期待高手指点,想学习一下的象我一样的菜鸟们,请帮忙up.谢谢
 
后退
顶部