-1

For example: I have procedure, that doing something, after click on Button1. How can i handle onclick event from button, without code in Button1Click? I need dynamically add event for Button1?

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure MyTest;
    procedure OutData(Sender: TObject);
    procedure FormClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}



procedure TForm1.FormClick(Sender: TObject);
begin
  MyTest; // Start up Main
end;

procedure TForm1.MyTest; // Main

begin
  Button1.OnClick := OutData;
end;

procedure TForm1.OutData(Sender: TObject);
begin
  ShowMessage('Button clicked!');
end;

end.

Ok, it work for one event, but if i need handle, two, three event, or event with parameters like OnMouseDown?

9
  • 1
    You need the code to run in an event handler. Hoping that you will be able to avoid that is not constructive. You can add the event handler at runtime or designtime. What is behind the question though? As it stands, any answer is unlikely to help you with your problem because your problem is still hidden to us. Commented Mar 22, 2017 at 14:37
  • if i have undertood your question, you can assign an event with a procedure Commented Mar 22, 2017 at 14:39
  • 1
    However, if we knew the reason why you wanted to do this, we could probably help you a lot more. Commented Mar 22, 2017 at 14:48
  • 1
    It still makes no sense at all. Commented Mar 22, 2017 at 15:32
  • 1
    You may want to take a look at the documentation for creating events. Commented Mar 22, 2017 at 15:50

2 Answers 2

4

Events are references to an object's method. Each event is explicitly typed with certain parameters. The most common type TNotifyEvent has the parameters (Sender: TObject) such as what you see on the OnClick event.

Other events however have other sets of parameters. OnMouseDown for example is a TMouseEvent which has the parameters (Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer). You have to be sure the parameters of your procedure match that of the event type.

Here's essentially how everything is set up behind the scenes...

type
  TNotifyEvent = procedure(Sender: TObject) of object;

  TMouseEvent = procedure(Sender: TObject; Button: TMouseButton;
    Shift: TShiftState; X, Y: Integer) of object;

  TControl = class(TComponent)
  ...
    property OnClick: TNotifyEvent read FOnClick write FOnCLick;
    property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;
  ...
  end;

In this case, you can also assign the same event handler to multiple different events of the same event type. For example, 5 different buttons with their OnClick event pointed to the same handler.

procedure TForm1.MyButtonClick(Sender: TObject);
begin
  //Do Something...
end;

procedure TForm1.MyButtonMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  //Do Something...
end;

Button1.OnClick := MyButtonClick;
Button2.OnClick := MyButtonClick;
Button3.OnClick := MyButtonClick;
Button4.OnClick := MyButtonClick;
Button5.OnClick := MyButtonClick;
Button1.OnMouseDown := MyButtonMouseDown;
Button2.OnMouseDown := MyButtonMouseDown;
Button3.OnMouseDown := MyButtonMouseDown;
Button4.OnMouseDown := MyButtonMouseDown;
Button5.OnMouseDown := MyButtonMouseDown;

If you want both of these events to do the same thing, you cannot assign the same event handler to events of different types, because they have different parameters. In that case, you will need to make both event handlers redirect to the same thing. Using the example, above, where you see //Do Something... in both places you would do the same exact thing. However, don't simply copy the code. Just make yet a third procedure, and make both event handlers call that one procedure.

procedure TForm1.MyButtonClick(Sender: TObject);
begin
  DoSomething;
end;

procedure TForm1.MyButtonMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  DoSomething;
end;

procedure TForm1.DoSomething;
begin
  //Do Something...
end;

On the other hand, the above example would make no sense in the real world though, because that would result in the same procedure being called twice for every button click. It's merely to demonstrate how to accomplish what you're trying to do using your example in your question.

Sign up to request clarification or add additional context in comments.

4 Comments

I Cant because Button1.OnClick := OutData; Button1.OnMouseDown := OutData; [dcc32 Error] Unit1.pas(41): E2009 Incompatible types: 'Parameter lists differ'
@DmitrySokolov You're not reading my answer closely enough. Please read it again.
@DmitrySokolov - I believe you're assigning the same event handler in all places you need. It's not working like this. Event handlers need to have the same signature
Is there a mechanism to handle several event handlers on the same event? e.g. two different components needs to react to the same OnClick, and there is no obvious place to create a function handler that calls both. I am speaking of some "Register() / Unregister()" or Observable mechanism. I can implement Observers myself, but...
0

you can use something like a observer pattern, where you use a "box" to put in methods and trigger these on button click.

Like that:

unit UFrmMain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Generics.Collections;

type
  TFrmMain = class(TForm)
    BtnClickMe: TButton;
    procedure FormCreate(Sender: TObject);
    procedure BtnClickMeClick(Sender: TObject);
  private
    FListOfButtonEvents : TList<TNotifyEvent>;

    procedure FirstButtonEvent(Sender : TObject);
    procedure SecondButtonEvent(Sender : TObject);
    procedure ThirdButtonEvent(Sender : TObject);
  public

  end;

var
  FrmMain: TFrmMain;

implementation

{$R *.dfm}

procedure TFrmMain.FormCreate(Sender: TObject);
begin
  FListOfButtonEvents := TList<TNotifyEvent>.Create();
  FListOfButtonEvents.Add(FirstButtonEvent);
  FListOfButtonEvents.Add(SecondButtonEvent);
  FListOfButtonEvents.Add(ThirdButtonEvent);
end;

procedure TFrmMain.BtnClickMeClick(Sender: TObject);
var
  Event : TNotifyEvent;
begin
  for Event in FListOfButtonEvents do
    Event(Sender);
end;

procedure TFrmMain.FirstButtonEvent(Sender : TObject);
begin
  ShowMessage('This is a First Method');
end;
procedure TFrmMain.SecondButtonEvent(Sender : TObject);
begin
  ShowMessage('This is a Second Method');
end;

procedure TFrmMain.ThirdButtonEvent(Sender : TObject);
begin
  ShowMessage('This is a Third Method');
end;

end.

I Hope i helped you

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.