10.3.4 为TDate类添加一个事件
我们已经为 TDate 类添加了一些属性,现在可以添加一个事件了。这个事件将非常简单。它将被称为 OnChange,可以用来警告组件的用户日期的值已经改变。要定义一个事件,我们只需定义一个与之相对应的属性,然后添加一些数据来存储事件指向的实际方法指针。这些就是 DateEvent 示例中添加到类中的新定义:
type
TDate = class
private
FOnChange: TNotifyEvent;
protected
procedure DoChange; dynamic;
public
property OnChange: TNotifyEvent read FOnChange write FOnChange;
end;
该属性的定义实际上非常简单。使用该类的开发人员可以为属性赋新值,从而为 FOnChange 私有字段赋值。程序启动时,该字段一般不会被分配,因为事件处理器是为组件的用户而不是组件编写者准备的。换句话说,TDate 类只需接受一个事件处理器,并在日期值发生变化时调用存储在 FOnChange 字段中的方法。当然,只有当事件属性已被赋值时,调用才会发生。
DoChange 方法(声明为动态方法,这是传统的事件触发方法)进行了测试和方法调用:
procedure TDate.DoChange;
begin
if Assigned(FOnChange) then
FOnChange(Self);
end;
注意 你可能还记得第 8 章的内容,动态方法类似于虚拟方法,但使用了不同的实现方式,以稍慢的调用速度为代价减少了内存占用。
每次值更新时,DoChange 方法都会被调用,如下代码所示:
procedure TDate.SetValue(Y, M, D: Integer);
begin
FDate := EncodeDate(Y, M, D);
// Fire the event
DoChange;
end;
现在,如果我们看一下使用该类的程序,就可以大大简化其代码。首先,我们在窗体类中添加一个新的自定义方法:
type
TDateForm = class(TForm)
...
procedure DateChange(Sender: TObject);
该方法的代码只是用 TDate 对象 Text 属性的当前值简单地更新标签:
procedure TDateForm.DateChange;
begin
LabelDate.Text := TheDay.Text;
end;
然后在 FormCreate 方法中委派该事件处理器:
procedure TDateForm.FormCreate(Sender: TObject); begin
TheDay := TDate.Init(7, 4, 1995);
LabelDate.Text := TheDay.Text;
// Assign the event handler for future changes
TheDay.OnChange := DateChange;
end;
好吧,这似乎是个大工程。当我告诉你事件处理程序会为我们节省一些代码时,我是在撒谎吗?不。现在,在我们添加了一些代码后,当我们更改对象的某些数据时,就可以完全忘记更新标签了。下面是其中一个按钮的 OnClick 事件处理器:
procedure TDateForm.BtnIncreaseClick(Sender: TObject);
begin
TheDay.Increase;
end;
其他许多事件处理器中也有同样的简化代码。一旦我们安装了事件处理器,我们就不必记得要不断更新标签了。这就消除了程序中大量潜在的错误。还要注意的是,由于这不是一个安装在开发环境中的组件,而只是一个类,因此我们必须在开始时编写一些代码。使用组件时,只需在对象检查器中选择事件处理器,然后编写一行代码即可更新标签。仅此而已。
这就引出了一个问题:在 Delphi 中编写一个新的组件有多难?
注意 本书并不深入探讨编写自定义组件的细节,而只是对属性和事件的作用以及编写组件作一个简短的介绍,因为对这些功能的基本了解对每个 Delphi 开发人员来说都是非常重要的。