英文:
Delphi - Adding onclick to a button created at runtime
问题
I understand that you want to set the onclick
event of the buttons to call another procedure passing in the fname
parameter. To achieve this, you can use an anonymous method (a feature introduced in recent versions of Delphi) to create a custom event handler. Here's how you can do it:
F1button.OnClick :=
procedure(Sender: TObject)
begin
AnotherProcedure(fname);
end;
By using an anonymous method, you can call AnotherProcedure(fname)
when the button is clicked, passing the fname
parameter as desired.
Make sure you have a recent version of Delphi that supports anonymous methods for this to work.
英文:
I have a procedure that creates a customtitlebar
and titlebarpanel
at runtime for any form name passed to it. The purpose of this is to handle the creation automatically for a bunch of different forms without having to worry about the current form control positions. This code shuffles all controls down automatically so they are not covered by the titlebarpanel
.
This code works. Call this procedure from any form's oncreate
adds 2 buttons to the form titlebar area.
procedure CreateTitleBarPanel(fname:tform);
var titlebarpanel:ttitlebarpanel;
F1button,F12button:tspeedbutton;
i:integer;
begin
fname.customtitlebar.enabled:=true;
titlebarpanel:=ttitlebarpanel.create(fname);
titlebarpanel.parent:=fname;
titlebarpanel.Visible:=true;
fname.customtitlebar.control:=titlebarpanel;
F1button:=tspeedbutton.create(titlebarpanel);
F1button.parent:=titlebarpanel;
F1button.top:=10;
F1button.height:=fname.customtitlebar.height-15;
F1button.width:=F1button.height;
//this is the problem
F1button.onclick:=how??
F12button:=tspeedbutton.create(titlebarpanel);
F12button.parent:=titlebarpanel;
F12button.top:=10;
F12button.height:=fname.customtitlebar.height-15;
F12button.width:=F12button.height;
F12button.left:=fname.customtitlebar.clientrect.width - F1button.Width - 8;
F1button.left:=F12button.left - F1button.Width - 8;
//move all form components down to match the titlebar height
for i:=0 to fname.ComponentCount-1 do
begin
try
(fname.Components[i] as TControl).top:=(fname.Components[i] as TControl).top+fname.customtitlebar.height;
except
//control does not have a top property, so skip it
end;
end;
end;
My issue is that I want the onclick for the buttons to call another procedure passing in the fname, so eg something like
F1button.onclick:=AnotherProcedure(fname);
That doesn't work though. E2010 Incompatible types: 'TNotifyEvent' and 'procedure, untyped pointer or untyped parameter
Can anyone explain how I can get this to work? Button created at runtime, when clicked I want it to call AnotherProcedure(fname);
(this procedure is the same unit as the CreateTitleBarPanel
procedure if that helps.
Thanks for any help.
答案1
得分: 3
TSpeedButton.OnClick
是一个事件处理程序(继承自Vcl.Controls.TControl.OnClick
),其类型为TNotifyEvent
。
类型定义:
TNotifyEvent = procedure(Sender: TObject) of object;
这意味着您必须在一个对象上定义一个接受TObject
参数的过程(可以是您的窗体或任何其他对象)。
例如:
TMyForm = class(TForm)
public
procedure MyOnClick(Sender: TObject);
end;
...
procedure TMyForm.MyOnClick(Sender: TObject);
begin
end;
然后,您可以将它分配为您的按钮的OnClick
事件处理程序,如下所示:
F1button.OnClick := MyOnClick;
英文:
TSpeedButton.OnClick
is an event handler (inherited from Vcl.Controls.TControl.OnClick
) and its type is TNotifyEvent
.
Type definition:
TNotifyEvent = procedure(Sender: TObject) of object;
This means that you have to define a procedure accepting a TObject
parameter on an object (it may be your form or any other object).
For example:
TMyForm = class(TForm)
public
procedure MyOnClick(Sender : TObject);
end;
...
procedure TMyForm.MyOnClick(Sender : TObject);
begin
end;
Then you'll be able to assign it as the OnClick
event handler of your button in this way:
F1button.OnClick := MyOnClick;
答案2
得分: 1
无法按照您所写的方式进行操作。
按钮的OnClick
事件是指向具有类型TNotifyEvent
的过程的链接。这意味着首先,该过程必须只有一个类型为TObject
的参数,其次,该过程必须是某个对象的方法。
如果您想要实现与您所写的类似的行为 - 您需要将此方法添加到您传递给CreateTitleBarPanel()
的每个窗体中,并将其分配给您的按钮,或者您需要具有具有指定行为的全局对象的方法。类似于以下内容:
type
TMyButtonsClickHandler = class(TObject)
public
procedure DoButtonClick(Sender: TObject);
end;
var
MyButtonsClickHandler: TMyButtonsClickHandler;
implementation
{ TMyButtonsClickHandler }
procedure TMyButtonsClickHandler.DoButtonClick(Sender: TObject);
var
fname: TCustomForm;
begin
// Sender必须是我们的其中一个按钮,请确保
if Sender is TSpeedButton then
begin
// 获取我们按钮的窗体
fname := GetParentForm(TSpeedButton(Sender), true);
// 以表单对象作为输入参数调用您的功能,正如您所要求的
AnotherProcedure(fname);
end;
end;
initialization
// 在任何调用之前创建我们的全局对象
MyButtonsClickHandler := TMyButtonsClickHandler.Create;
finalization
// 在结束时销毁我们的全局对象
FreeAndNil(MyButtonsClickHandler);
end.
当您拥有了这个全局对象后,您可以在CreateTitleBarPanel()
函数中使用F1button.OnClick := MyButtonsClickHandler.DoButtonClick;
,然后单击任何这些按钮将运行您的AnotherProcedure()
,并将父窗体作为参数传递。
英文:
You can't do it exactly as you wrote.
A button's OnClick
event is a link to a procedure with type TNotifyEvent
. That means that first of all this procedure must have only one parameter with type TObject
, and second this procedure must be a method of some object.
If you want to have similar behavior as you wrote - you need to add this method to every form that you pass into CreateTitleBarPanel()
and assign it to your buttons, or you need to have some global object with your method with specified behavior. Something like that:
type
TMyButtonsClickHandler = class(TObject)
public
procedure DoButtonClick(Sender : TObject);
end;
var
MyButtonsClickHandler : TMyButtonsClickHandler;
implementation
{ TMyButtonsClickHandler }
procedure TMyButtonsClickHandler.DoButtonClick(Sender: TObject);
var
fname : TCustomForm;
begin
//Sender must by one of our buttons, make sure that
if Sender is TSpeedButton then
begin
//get form of our button
fname := GetParentForm(TSpeedButton(Sender), true);
//calling your functionality with form object as IN param, as you ask
AnotherProcedure(fname);
end;
end;
initialization
//create our global object before any calls
MyButtonsClickHandler := TMyButtonsClickHandler.Create;
finalization
//destroy our global object in finalization
FreeAndNil(MyButtonsClickHandler);
end.
When you will have this global object, you can make F1button.OnClick :=
inside your
MyButtonsClickHandler.DoButtonClick;CreateTitleBarPanel()
function, and then click on any of these buttons will run your AnotherProcedure()
with the parent form as the parameter.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论