I create buttons at runtime and would like to be able to set custom OnClick event that each button would pass it's own custom values when clicked:
I get error when trying to assiign custom OnClick procedure:
E2010 Incompatible types: 'TNotifyEvent' and 'procedure, untyped pointer or untyped parameter'
here is how i use it:
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;
How can I use custom click event, procedure, so I can pass values specific to the button, when button is clicked?
EDIT:
right now I use the CustomOnClick:
procedure TForm1.CustomOnClick(Sender: TObject);
begin
myOnClick(Sender,TControl(Sender).Tag);
end;
vBtn.OnClick:=Form1.CustomOnClick; // works, but only accepts Sender parameter
As David suggested, I already use Tag property. Now I need more info and would like to get rid of this 'middle man' CustomOnClick and call myOnClick directly.
Method 1
You can store "button info" separatelly, like there:
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;
Method 2 As David said, more preferred.
"Expand" TButton class and add needed properties to new class:
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;
Method 3, unwanted
Use dynamic allocated memory for store TButtonInfo from Method 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;