五、复合控件
复合控件是
Delphi
控件中非常重要的一种控件,复合控件就是将两个或两个以上的控件重新组合成一个新的控件。例如
TspinEdit
、
TlabeledEdit
、
TDBNavigator
等就是复合控件,
TDBNavigator
其实就是在一个
Panel
放上若干个
Button
而已。制作一个复合控件时,我们一般从
TwinControl
派生控件。
我们这次做的控件是拥有一个
Edit
编辑框和一个
Button
按钮的复合控件,在用户在编辑框中输入文字的过程中,
Button
将随时显示编辑框中文字的长度。我们把控件的源码先展示给大家。
unit EditButton;
interface
uses
SysUtils, Classes, Controls, StdCtrls, Messages;
type
TEditButton = class(TWinControl)
private
FEdit: TEdit;
FButton: TButton;
FText: string;
procedure FSetText(AValue: string);
procedure OnEditChange(Sender: TObject);
protected
procedure WMSize(var Msg: TMessage);message WM_SIZE;
public
constructor Create(AOwner: TComponent);override;
destructor Destroy;override;
published
property Text: string read FText write FSetText;
end;
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Linco', [TEditButton]);
end;
constructor TEditButton.Create(AOwner: TComponent);
begin
inherited;
FEdit := TEdit.Create(nil);
FEdit.Parent := self;
FEdit.Top := 0;
FEdit.Left := 0;
FEdit.Height := Height;
FEdit.Width := Width div 2;
FEdit.OnChange := OnEditChange;
FButton := TButton.Create(nil);
FButton.Parent := self;
FButton.Top := 0;
FButton.Left := Width div 2;
FButton.Height := Height;
FButton.Width := Width div 2;
end;
destructor TEditButton.Destroy;
begin
FEdit.Free;
FButton.Free;
inherited;
end;
procedure TEditButton.FSetText(AValue: string);
begin
FEdit.Text := AValue;
end;
procedure TEditButton.OnEditChange(Sender: TObject);
begin
FButton.Caption := IntToStr(Length(FEdit.Text));
end;
procedure TEditButton.WMSize(var Msg: TMessage);
begin
FEdit.Height := Height;
FEdit.Width := Width div 2;
FButton.Left := Width div 2;
FButton.Height := Height;
FButton.Width := Width div 2;
end;
end.
代码解释:
(
1
)、我们首先定义了两个变量
FEdit: TEdit;
FButton: TButton;
分别代表复合控件中的文字编辑框和按钮。
(
2
)所谓复合控件说简单一点就是在一个共同的基板上将组成复合控件的各个控件(可以叫做子控件)画出来。所以我们在构造函数中建立各个子控件,然后分别设定它们的位置等属性。
以文字编辑框为例:
FEdit := TEdit.Create(nil);
的作用是建立编辑框控件。如果
Create
的参数指定为
nil,
则子控件在设计状态是可以响应用户的操作的;而如果设定为
self(
即设定子控件的父控件为基板
)
,则子控件在设计时时不可响应用户操作的,如果设定为
self
则析构函数中就不用
Fedit.Free
来销毁对象了,对象会自动销毁。
FEdit.Parent := self;
的作用是设定子控件的父控件,如果没有这一句则控件是无法显示的。
FEdit.Top := 0;
FEdit.Left := 0;
FEdit.Height := Height;
FEdit.Width := Width div 2;
这四句是设定控件在基板上的相对位置的,这里的
Top,Left
不是相对于窗体的,而是相对于基板的。
FEdit.OnChange := OnEditChange;
则是设定编辑框控件的
OnChange(
文字改变事件
)
的处理句柄为
OnEditChange
;
(1)
用户有可能在设计时或运行时通过代码改变控件的大小,这时控件中子控件的顺序就会变得乱七八糟,所以需要相应控件的
WM_SIZE
事件(控件大小发生变化的事件)重新设定子控件的位置,大小等。函数
WMSize
的作用就是这样的。
安装控件后发现控件已经可以正确运行了,但是还有一个问题,就是这个控件没有了
Onclick,Onchange
等必须的属性。我们只要为控件增加事件处理句柄属性,然后把事件处理句柄属性的读写方法都指向子控件的事件处理句柄属性即可。例如我们为控件增加
OnClick
事件,这个事件发生在用户单击按钮时,我么只要在
Pulished
部分增加如下代码:
property OnClick: TnotifyEvent read GetOnClick write SetOnClick
在
Private
中增加如下方法声明:
function GetOnclick: TnotifyEvent;
procedure SetOnclick(AValue: TnotifyEvent);
这两个方法的实现分别为:
function TeditButton. GetOnclick: TnotifyEvent;
begin
result := Fbutton.Onclick;
end;
procedure TeditButton. SetOnclick(AValue: TnotifyEvent);
begin
Fbutton.OnClick := Avalue;
end;
思考题:
1
、做一个模仿播放器中的操作按钮的复合控件,控件由三个按钮组成,分别是“播放”、“暂停”、“停止”,请按照正常的逻辑关系,处理这三个按钮的可用
/
不可用关系。(提示:可以参考
TDBNavigator
的源代码)
转载于:https://blog.51cto.com/cownew/87633