无名称构件的使用
我曾在许多Delphi资料中看到这样的说法:每一个Component都必须有一个不为空的Name,用于和其他Component相区分。过去我也对这种说法深信不疑。但是看过《Mastering Delphi 6》后,我知道我错了。Component的Name属性可以是空的,特别是对于Menu Separator,Static Label,Bevel,Shape和Panel等等。虽然IDE会给所有的构件起一个默认的名称,不过你可以在Object Inspector中把它的Name清空,这样的后果是:
1.构件在Object Inspector和Object TreeView中将变成Unnamed或者Component<0>这样的表示方法;
2.该构件的声明将从Form的声明中完全删除;
3.如果用View As Text看看.DFM文件的定义,发现无名称的Component对象定义为这样的形式:
object : TMenuItem
caption = '-'
end
而一般的声明为:
object File1: TMenuItem
caption = 'File'
end
这个特点的真正好处在于,可以让Form的声明简洁许多,再也不会充斥大量无用的N1,N2之类标识符,从而混淆你的视线。当然,可执行文件的大小也会稍有减少。
不过,假如将Form上面所有Label的Name都设为空,那么运行该程序将产生一个错误,因为编译器看到声明中没有Label,所以不会将TLabel的有关TLabel的库函数连接进来。(编译器在绝大多数时候都很聪明,不过这个时候只能说它是自作聪明。)解决办法是至少保留一个有名字的Label。
我们甚至可以手动将Form中某个Component的声明删除。不用担心,在Form建立起来的时候这个Component不会消失,只是不能够用通常的办法来引用它了。真的有需要的时候,可以用Form1.FindComponent('Button1')这样的方法找到特定的构件。如果Form中的构件实在太多,可以用这个技巧来删除一部分不太重要的声明,保持单元的简洁。
其实,要减少Label声明的数量,用Delphi 6中新增的LabledEdit是一个行之有效的办法,而且LabeledEdit可以简化窗体的布局管理。不过,LabeledEdit只对Edit有效。要减少其他不需要响应事件和处理输入的构件(如Menu Separator,Panel和Bevel等等)的声明,就只能用这种方法。不同于一般的procedure或者function,在Delphi中属于某个类的方法称为method,它们的声明一般为AProcMethod:procedure(Sender:TObject) of object;
为什么一定要加上of object呢?实际上,Object Pascal中一般的函数指针就相当于普通的指针,而AProcMethod则是一个对指针,它在Delphi中有一个对应的类型:TMethod。
TMethod=record
Data, Code:Pointer;
end;
所以,我们在单元中可以这样:
procedure TForm1.Button1Click2(Sender:TObject);
begin
ShowMessage('Click2!');
end;
procedure TForm1.FormCreate(Sender:TObject);
var
Method:TMethod;
begin
Method.Data := Self;
Method.Code := MethodAddress('Button1Click2');
Button1.OnClick := TNotifyEvent(Method);
end;
当然,实际上只需要Button1.OnClick=Button1Click2即可;不过,这样可以让你明白在幕后发生的事情。值得注意的一点是,Button1Click2应该声明在published段(或者和其他构件的声明放在一起,因为默认作用域就是published),以便编译器为它产生RTTI信息,否则程序可能达不到预期的效果。