5

I'm having a form with certain components whose are having event handlers. Now I would like to move those event handlers (those methods) to a separate unit still being able to assign them to component events through the Object Inspector at design time.

Is it possible to make a separate unit only for event methods, so that the Object Inspector allows me to assign them at design time ?

Let's say if I would make that unit with a public procedure:

unit Unit2;

interface

procedure ButtonClick(Sender: TObject);

implementation

procedure ButtonClick(Sender: TObject);
begin
  // do something here
end;

end.

Or with a class with published method like this:

unit Unit2;

interface

type
  TMyClass = class
  published
    procedure ButtonClick(Sender: TObject);
  end;

var
  MyClass: TMyClass;

implementation

{ TMyClass }

procedure TMyClass.ButtonClick(Sender: TObject);
begin
  // do something here
end;

end.

How to make a separate unit for event methods, which IDE allows me to assign to component events at design time ? Like for instance:

enter image description here

TLama
  • 75,147
  • 17
  • 214
  • 392
  • 4
    OK. Go ahead. What's stopping you from doing that? – Rob Kennedy Aug 14 '13 at 19:20
  • i can't assigned this event in Button in design time. ¿Do you have any example? – user2683734 Aug 14 '13 at 19:43
  • 5
    It's a shame that this question has been put on hold, firstly because it is actually quite clear what the OP is asking and secondly, the fact that it has prevents anyone providing an explanation (which is understandable to a beginner) which requires more space that a comment permits. – MartynA Aug 14 '13 at 20:34
  • @MartynA, in my view it's also clear. Let's try to put it back to the reopen queue. I'm also wondering what criteria needs to be met for seeing an event method in Object Inspector's event combo. At least you'd need to have component registered for a design time usage, the method must be published and this component must (?) be placed on a form or data module... And something else is needed ? – TLama Aug 14 '13 at 21:06
  • @TLama, thanks. The OP may have noticed that if Unit1 uses Unit 2, the Object Inspector allows you to set a property of TForm1 to an object that's on Form2, so it's maybe puzzling what the OI won't let you do in terms of writing the event code in another unit, which seems at odds with what it will let you do with object properties. Being a newbie here, I've no idea how to go about putting the Q on the re-open queue, though. – MartynA Aug 14 '13 at 21:17
  • @Martyn, the question isn't clear to me at all. I don't see what obstacle this user is trying to overcome. There seems to be some difficulty in assigning it as design time; what it the nature of that difficulty? Someone who knows should [edit] the question to say so. Otherwise, I think what I asked in my first comment still stands. – Rob Kennedy Aug 14 '13 at 21:19
  • @Rob, sorry, I wasn't meaning to be controversial. I took his question to be "Seeing as the Object Inspector won't let me write a method in Form2 to handle an event in TForm1, how do I go about doing that myself?" ("assign them to the components of my *main form* at design time.. instead of Button1Click wish to put something like *Unit2*.ButtonClick") – MartynA Aug 14 '13 at 21:28
  • Everyone seems to be *assuming* that the subroutine in Unit2 is misdeclared — that it's a standalone procedure instead of a method. That might be true, but is *that* the reason it doesn't show up in the Object Inspector? We can't know since we haven't been shown Unit2. It's possible for the Object Inspector to display event handlers from other units. If we were given more information about Unit1 and Unit2, we might be able to explain why the Object Inspector isn't showing everything we'd expect it to. But since there isn't a good problem description, it's unclear what sort of answer is wanted. – Rob Kennedy Aug 14 '13 at 21:47
  • I wasn't assuming that, just that the OP had noticed that dbl-clicking on an event of TForm1 does not create a handler for it on TForm2, which prompts the question "Well, how do I do that, then?". Let's leave it there. – MartynA Aug 14 '13 at 21:55
  • @Rob, I've edited the question the way I think is asked. I hope I get it right. user2683734, could you review my edit of your question and let me know if I get it right, please ? – TLama Aug 14 '13 at 21:59
  • 1
    I think OP has been gone :-( – OnTheFly Aug 15 '13 at 11:43

1 Answers1

4

Most events are method pointers. That means they point to a procedure or function in a class. So you cannot just attach the procedure Unit2.ButtonClick to an on click event of a button, but you can write a class that implements the event handler, something like this:

type
  TMainFormButtonEventHandler = class
    procedure ButtonClick(Sender: TObject);
  end;

procedure TMainFormButtonEventHandler.ButtonClick(Sender: TObject);
begin
  ShowMessage('Clicked');
end;

Now you can create such an object and link it to the event:

handler := TMainFormButtonEventHandler.Create;
Form1.Button1.OnClick := handler.ButtonClick;

I don't think this is the best application structure, though. I would not hook into GUI elements of a form from outside the form's unit. But if you would like to do so, this is how it's done.

If you're looking for separation of GUI and logic, have a look at actions. A TAction (wrapped in an ActionList), is the first layer of abstration between a GUI component like a button and the action code it performs.

The convenient thing is that you can create those actions at design time as well, and attach them to a button or other control. Instead of writing code for ButtonClick, you write code for ActionExecute (the OnExecute event of the action). The button knows that when it is clicked, it should execute its related action.

GolezTrol
  • 114,394
  • 18
  • 182
  • 210
  • i'm sorry, i'm novice in delphi.. but where put **handler := TMainFormButtonEventHandler.Create;** **Form1.Button1.OnClick := handler.ButtonClick;*** – user2683734 Aug 14 '13 at 20:07
  • It depends. Somewhere in the initialization code of your application. But anyway, that is a runtime solution, not a design time solution like you asked. I think the closest thing to a design time solution is the use of actions, like I described at the bottom of my answer, although it is not a drop-in solution for any event. – GolezTrol Aug 14 '13 at 20:09
  • 2
    It **IS** possible to use non-class functions as handlers for events that expect object methods. The trick is to give the function an extra starting parameter to receive a `Self` value from the event, and to use the `TMethod` record to help you assign the function to the event (which also allows you to specify what value the `Self` parameter will actually receive, which can be anything you want if not a real object). However, this approach **DOES NOT** not work at design-time, only at run-time. – Remy Lebeau Aug 14 '13 at 22:22