运行是动态生成控件的问题(100分)

  • 主题发起人 主题发起人 baorenlong
  • 开始时间 开始时间
B

baorenlong

Unregistered / Unconfirmed
GUEST, unregistred user!
我刚刚学习Delphi,有一个问题不太懂,动态生成控件怎么添加事件?我看了一些资料都
特别简略:
添加了一个Button1在Form1上Button1的onclick事件如下代码:

procedure TForm1.Button1Click(Sender: TObject);
var
Button2: TButton;
begin
Button2:=TButton.Create(Self);
Button2.Parent:=Self;
Button2.Click:=Mycode;
end;

其中的Button2.Click 事件代码Mycode。我不太懂Mycode如何写,在哪写,还要在哪声明一下吗?
 
procedure TForm1.Mycode(Sender: TObject);
begin
...//跟普通的事件响应过程一样
end;

procedure TForm1.Button1Click(Sender: TObject);
var
Button2: TButton; //注意:如果在这里定义变量,
//该按钮占用的资源可能永远不能释放,建议把这个定义放在TForm1的类界面
begin
Button2 := TButton.Create(Self);
Button2.Parent := Self;
Button2.OnClick := Mycode;
~~~~~~//是OnClick
end;
 
事件实际就是指向对象方法(一般是过程)的指针,

TNotifyEvent = Procedure (Sender: TObject) of Object;
则 TNotifyEvent 类型的变量就是指向定义为
procedure TClassName.MethodName(Sender: TObject) 格式的类方法的指针。

TButton 的 OnClick 属性是 TNotifyEvent 类型, 则只要是符合以上格式的类方法
如 TMyForm.MyBtnClick(Sender: TObject) 就可以直接赋给它的 OnClick 属性:
...
Button2.OnClick := MyForm.MyBtnClick;//注意虽然是指针,但不必用 @MyForm.MyBtnClick
取消事件则 Button2.OnClick := nil;
另,JohnsonGuo 对于Button2为局部变量,资源不能释放的说法我不赞同,
Button2.Create(Self);
已经指定了 Button2 的 Owner 为 Self 即 Form1,因此 Form1 被 Free 掉时,Button2
同时会被 Free 掉,没有资源不释放的问题。
 
我这里先谢谢bbkxjy与JohnsonGu但是还没解决我的具体问题。二位只是在理论上说明
如何动态创建控件的事件添加方法但是下边的的代码在哪添加呢?
procedure TForm1.Mycode(Sender: TObject);
begin
...//跟普通的事件响应过程一样
end;

下面是我的源码:

unit Unit1;

interface

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

type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}


procedure TForm1.Button1Click(Sender: TObject);
var
Button2: TButton;
begin
Button2:=TButton.Create(Self);
Button2.Parent:=Self;
Button2.Click := Mycode;
end;

end.
我在以下几个地方加入代码,结果Delphi总是不让编译。

unit Unit1;

interface

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

type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
//1、我最先在这里声明,但好像不对,后来我想明白了。此时Button2还没有被建立。
private
{ Private declarations }
public
{ Public declarations }
{2、我的第二次在这里定义了
procedure TForm1.Mycode(Sender: TObject);
begin
...//跟普通的事件响应过程一样
end;
事件但是还是不行,为什么,我就不知道了。}

end;

var
Form1: TForm1;

implementation

{$R *.DFM}

//3、我在这声明了事件,但还是不行,原因同1
procedure TForm1.Button1Click(Sender: TObject);
var
Button2: TButton;
begin
Button2:=TButton.Create(Self);
Button2.Parent:=Self;
Button2.Click := Mycode;
end;
//4、我后来在这里定义事件代码Mycode但是还是不行。
end.

于是,我不知道如何具体应用。回答我的两位,同我以前看过的资料都是一样的只是
理论上告诉我是可行的。问题没有解决但是我还是感谢二位。也许是我太笨找不到放
这段的地方;也许是这个问题没有太大的实际意义,所以,大家都不太注意。也许是
我是初学者,对其他的地方不熟,代码就不是放在Unit1中的;也许......
太多的也许促使我很不自信,不知道学习Delphi之路到底在何方呢?请大家指一条明路
给我吧!!!



 
应该这样
unit Unit1
unit Unit1;

interface

uses
Windows,...,StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
//这一节声明由Delphi自动维护,实际上相当于published节,如设计时放
//在Form上的控件和在对象观察器事件页对应事件属性中双击生成的事件
//的声明都在这里,一般不要手工在这里增删属性或方法
private
{ Private declarations }
//在这里声明的字段、属性和方法是类私有的,对于该Unit文件之外的过程而言
//是不可见
public
{ Public declarations }
//在这里声明的字段、属性和方法是类私有的,对于程序中所有的过程而言都是
//可见的
//应该这样声明类方法 MyCode:
procedure Mycode(Sender: TObject);
//procedure TForm1.Mycode(Sender: TObject);
//begin
// ...
//end; 这样子是定义而不是声明,应该放在 implementation 段;声明只是说明原型
end;

//然后在 implementation 段定义 MyCode :
implementation

procedure TForm1.Mycode(Sender: TObject);
begin
...//跟普通的事件响应过程一样
end;

end;
不要紧的,慢慢来,多看点书,多动手,建议先了解Object Pascal的常用语法,
如单元的布局,工程文件的布局,如何定义类...等。
 
谢谢bbxjy,也谢谢JohnsonGuo。我的问题已经解决了。
 
在 implementation 段定义 MyCode :

procedure TForm1.Mycode(Sender: TObject);
begin
...//跟普通的事件响应过程一样
end;

其中可不可以引用刚刚动态建立的控件的属性?
 
那要看你的新建立的类变量的作用域了,这里类变量是 Button2,如果这样声明它:
TForm1 = Class(TForm)
...
private (或 public)
Button2: TButton; //私有的类成员变量,对所有TForm1的所有成员方法都是可见的
...
end;
则 Button2 就是类成员变量,MyCode是类成员方法,当然可以直接访问Button2,
如果你的 Button2 是在另一成员方法中声明的:
procedure TForm1.Button1Click(Sender: TObject);
var
Button2: TButton;
begin
Button2:=TButton.Create(Self);
...
end;
则这个 Button2 是 Button1Click 的局部变量,对 MyCode 而言就不可见了。
如果你在这两个地方都声明了 Button2,则你在 Button1Click 中创建的 Button2 与你在
TForm1 声明的 Button2 并不是同一个 TButton 对象,后者实际上还是 nil,而 MyCode
能访问的 Button2 是后者,此时若 MyCode 直接访问 Button2 的属性或方法将引起非法
访问的异常。因此你的 Button2 应在 TForm1 类声明中声明,在 MyCode 中访问 Button2
前还要应检查它是否为 nil。
另外,在这里你其实可以这样访问新建的控件:
procedure TForm1.MyCode(Sender: TObject);
begin
//Sender 是触发事件的对象,这里因为你把事件赋给
//了Button2,因此 Sender 实际上是 Button2
if Sender is TButton then //检验 Sender 是否为 TButton 类的变量
with TButton(Sender) do
begin
Caption := 'aaa'; //这就将 Button2 的 Caption 设为 'aaa'
end;
end;
通过这种方法,就不需要 Button2 变量对 MyCode 是可见的,即你不必将 Button2
声明为类成员变量了,直接在 Button1Click 中将 Button2 声明为局部变量就可以了。
 
特别感谢你bbkxjy。我有个冒昧的请求:可不可以把你的OICQ和Email留给我。以后,如
我有问题可以随时请教!我的OICQ是3578241。Email是baorenlong@sohu.com或
baorenlong@yeah.net
 
后退
顶部