自定义按钮OnClick事件
我在运行时创建按钮,并希望能够自定义设置OnClick事件,单击时每个按钮将通过它自己的自定义值:自定义按钮OnClick事件
试图assiign定制的OnClick过程时,我得到错误:
E2010 Incompatible types: 'TNotifyEvent' and 'procedure, untyped pointer or untyped parameter'
这是我如何使用它:
procedure myOnClick(Sender:TObject; Info1:string; info2:integer);
begin
// process info1, info2 based on which button is Sender
end;
procedure TForm1.Button1Click(Sender: TObject);
var vBtn:Tbutton;
Idx:integer;
vStr:string;
begin
// ...
// create btn
vBtn := Tbutton.Create(nil);
vBtn.Parent := Form1.ButtonsPanel;
vBtn.Tag := Idx;
vBtn.OnClick:=myOnCLick(self,vStr,vBtn.Tag);
// assign btn
//...
end;
如何使用自定义点击事件,过程,所以我可以通过值SPECI按下按钮时,点击按钮?
编辑:
现在我用的是CustomOnClick:
procedure TForm1.CustomOnClick(Sender: TObject);
begin
myOnClick(Sender,TControl(Sender).Tag);
end;
vBtn.OnClick:=Form1.CustomOnClick; // works, but only accepts Sender parameter
当大卫的建议,我已经使用Tag属性。现在我需要更多信息,并希望摆脱这个'中间人'CustomOnClick并直接调用myOnClick。
方法1
您可以存储 “按钮信息” separatelly,像有:
type
TButtonInfo = record
info1: string;
info2: Integer;
info3: Double;
constructor Create(const AInfo1: string; AInfo2: integer; AInfo3: Double);
end;
TButtonInfoDictionary = class(TDictionary<TObject,TButtonInfo>)
end;
TForm6 = class(TForm)
.....
private
{ Private declarations }
FButtonInfoDict: TButtonInfoDictionary;
procedure OnButtonClick(Sender: TObject);
public
{ Public declarations }
destructor Destroy; override;
end;
implementation
constructor TButtonInfo.Create(const AInfo1: string; AInfo2: integer;
AInfo3: Double);
begin
Info1:=AInfo1;
Info2:=AInfo2;
Info3:=AInfo3;
end;
procedure TForm6.btnAddNewButtonClick(Sender: TObject);
var
btn: TButton;
begin
if not Assigned(FButtonInfoDict) then
FButtonInfoDict:=TButtonInfoDictionary.Create;
btn:=TButton.Create(nil);
btn.Parent:=Self;
btn.Align:=alTop;
btn.Caption:='btn'+FButtonInfoDict.Count.ToString;
btn.OnClick:=OnButtonClick;
FButtonInfoDict.Add(btn, TButtonInfo.Create(FButtonInfoDict.Count.ToString, FButtonInfoDict.Count, 0));
end;
destructor TForm6.Destroy;
begin
FreeAndNil(FButtonInfoDict);
inherited;
end;
procedure TForm6.OnButtonClick(Sender: TObject);
var
ButtonInfo: TButtonInfo;
begin
if Assigned(FButtonInfoDict) then
if FButtonInfoDict.TryGetValue(Sender, ButtonInfo) then
Caption:=ButtonInfo.Info1+' ' + ButtonInfo.info2.ToString;
end;
方法2正如大卫说,更优选的。
“展开” TButton的类和需要的属性添加到新的类:
type
TButton = class(Vcl.StdCtrls.TButton)
private
FInfo2: integer;
FInfo1: string;
public
property Info1: string read FInfo1 write FInfo1;
property Info2: integer read FInfo2 write FInfo2;
end;
TForm6 = class(TForm)
.....
private
{ Private declarations }
procedure OnButtonClick(Sender: TObject);
public
{ Public declarations }
end;
procedure TForm6.btnAddNewButtonClick(Sender: TObject);
var
btn: TButton;
begin
btn:=TButton.Create(nil);
btn.Parent:=Self;
btn.Align:=alTop;
btn.Caption:='btn'+Self.Tag.ToString;
btn.Info1:=Self.Tag.ToString;
btn.Info2:=Self.Tag;
btn.OnClick:=OnButtonClick;
Self.Tag:=Self.Tag + 1;
end;
procedure TForm6.OnButtonClick(Sender: TObject);
begin
if Sender is TButton then
Caption:=TButton(Sender).Info1+' ' + TButton(Sender).info2.ToString;
end;
方法3,不需要
使用动态分配的店面TButtonInfo从方法1内存:
PButtonInfo = ^TButtonInfo;
procedure TForm6.btnAddNewButtonClick(Sender: TObject);
var
btn: TButton;
pInfo: PButtonInfo;
begin
btn:=TButton.Create(nil);
btn.Parent:=Self;
btn.Align:=alTop;
btn.Caption:='btn'+Self.Tag.ToString;
btn.OnClick:=OnButtonClick;
New(pInfo); // once we have allocated memory, we need to release it after all.
// but we dont have event, where we can call Dispose(PButtonInfo(btn.tag));
// so, we have memory leak...
// You can change TButtonInfo declaration from record to class,
// and use .Create against New, but memory leak still there
pInfo.info1:=Self.Tag.ToString;
pInfo.info2:=Self.Tag;
btn.Tag:=NativeInt(pInfo);
Self.Tag:=Self.Tag + 1;
end;
procedure TForm6.OnButtonClick(Sender: TObject);
begin
if Sender is TButton then
Caption:=PButtonInfo(TButton(Sender).Tag).Info1+' ' + PButtonInfo(TButton(Sender).Tag).info2.ToString;
end;
太棒了!我认为方法2最适合用我的代码实现,让我看看。 –
'OnButtonClick'可以以不同的方式定义,而不是TForm(例子#2)?我想尽可能地将这些按钮放在单独的单元中 - 没有形式。这可能吗? –
@MikeTorrettinni,是的。但只作为任何类别的任何对象的方法,而不是正常的程序。你可以做'btn.OnClick:= myNewObjectOfSuperClass.ButtonClick' – kami
你不会补偿t他对事件的签名。他们传递给你,用石头写成。使用“标签”来保存特定于按钮的信息。在那里放一个指向记录的指针。或者是对类实例的引用。或TButton的子类,并将信息放在那里作为字段。后一种方法在一定程度上是首选。 –
或者创建一个vStr值的数组,并使用.'Tag'作为数组的索引。如果您需要更多信息,请使用记录阵列或对象列表等。 –
标签可以容纳一个指针,以便您可以在其中放入任何您喜欢的信息。 –