Recent

Author Topic: Setting events stored in other unit to controls  (Read 3280 times)

Gald

  • New Member
  • *
  • Posts: 47
Setting events stored in other unit to controls
« on: May 09, 2021, 06:06:38 pm »
Hello hello!

I trying to do something like this:

Code: Pascal  [Select][+][-]
  1. Label1.OnClick:=@LabelClick;

But the event LabelClick is on another unit.
None of this below is working.

Code: Pascal  [Select][+][-]
  1. Label1.OnClick:=@Unit2.LabelClick;
  2. Label1.OnClick:=Unit2.@LabelClick;
  3. Label1.OnClick:=Unit2.SomeClass.LabelClick;
  4. Label1.OnClick:=Unit2.SomeClass.@LabelClick;
  5. Label1.OnClick:=@Unit2.SomeClass.LabelClick;

Then, how can I do it?


Bart

  • Hero Member
  • *****
  • Posts: 4282
    • Bart en Mariska's Webstek
Re: Setting events stored in other unit to controls
« Reply #1 on: May 09, 2021, 07:25:15 pm »
Define "not working".
Compilation error?
Runtime error?
Something else?

Bart

Gald

  • New Member
  • *
  • Posts: 47
Re: Setting events stored in other unit to controls
« Reply #2 on: May 09, 2021, 07:47:29 pm »
Define "not working".

C:\Test\unit1.pas(37,20) Error: (4001) Incompatible types: got "<address of procedure(TObject);Register>" expected "<procedure variable type of procedure(TObject) of object;Register>"

There's also this hit info on Attachment.

jamie

  • Hero Member
  • *****
  • Posts: 4563
Re: Setting events stored in other unit to controls
« Reply #3 on: May 09, 2021, 08:32:24 pm »
seems to work for me.
Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormCreate(Sender: TObject);
  2. begin
  3.   Onclick := unit2.form2.Onclick;
  4. end;                                                
  5.  

You need to define from an instance of the class, not the class itself.
The only true wisdom is knowing you know nothing

Gald

  • New Member
  • *
  • Posts: 47
Re: Setting events stored in other unit to controls
« Reply #4 on: May 09, 2021, 09:23:33 pm »
Could you please look at this sample project?
I still having problems.

Handoko

  • Hero Member
  • *****
  • Posts: 4285
  • My goal: build my own game engine using Lazarus
Re: Setting events stored in other unit to controls
« Reply #5 on: May 09, 2021, 09:52:14 pm »
This works:

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Forms, StdCtrls;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     Button1: TButton;
  16.     Label1: TLabel;
  17.     procedure Button1Click(Sender: TObject);
  18.   private
  19.     procedure TheReplacement(Sender: TObject);
  20.   public
  21.  
  22.   end;
  23.  
  24. var
  25.   Form1: TForm1;
  26.  
  27. implementation
  28.  
  29. uses Unit2;
  30.  
  31. {$R *.lfm}
  32.  
  33. { TForm1 }
  34.  
  35. procedure TForm1.Button1Click(Sender: TObject);
  36. begin
  37.   Label1.OnClick := @TheReplacement;
  38. end;
  39.  
  40. procedure TForm1.TheReplacement(Sender: TObject);
  41. begin
  42.   OnClickReplacement(Sender);
  43. end;
  44.  
  45. end.

Code: Pascal  [Select][+][-]
  1. unit Unit2;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   StdCtrls, Graphics;
  9.  
  10. procedure OnClickReplacement(Sender: TObject);
  11.  
  12. implementation
  13.  
  14. procedure OnClickReplacement(Sender: TObject);
  15. begin
  16.   if not(Sender is TLabel) then Exit;
  17.   (Sender as TLabel).Font.Style := [fsBold];
  18. end;
  19.  
  20. end.

Just to warn you, don't use such trick too much. Or your code will be become spaghetti code:
https://en.wikipedia.org/wiki/Spaghetti_code

Gald

  • New Member
  • *
  • Posts: 47
Re: Setting events stored in other unit to controls
« Reply #6 on: May 09, 2021, 10:33:55 pm »
Just to warn you, don't use such trick too much.

 :o :o LOooolll

My goal was to do it a lot.
I have to find another way.

Gustavo 'Gus' Carreno

  • Hero Member
  • *****
  • Posts: 535
  • Professional amateur ;-P
Re: Setting events stored in other unit to controls
« Reply #7 on: May 09, 2021, 11:48:03 pm »
Hey Gald,

But the event LabelClick is on another unit.

I understand separation of concerns and the need to put things in little manageable boxes, but what I can't understand is why you want events from one form to be handled in some other unit.

In my point of view, a Label's event should reside on the same unit that declares it and that, at least for me, checks both these boxes: separation of concern and the put-things-in-little-boxes.

Can I, very politely, ask for an explanation on why would you want to bridge across a unit for an event?
I think there's a design flaw on your side that needs to be addressed, not shamed, but addressed :)

Cheers,
Gus
Lazarus 2.1.0(trunk) FPC 3.3.1(trunk) Ubuntu 21.04 64b Dark Theme
Lazarus 2.0.12(stable) FPC 3.2.2(stable) Ubuntu 21.04 64b Dark Theme
http://github.com/gcarreno

Handoko

  • Hero Member
  • *****
  • Posts: 4285
  • My goal: build my own game engine using Lazarus
Re: Setting events stored in other unit to controls
« Reply #8 on: May 10, 2021, 05:39:22 am »
My goal was to do it a lot.
I have to find another way.

You will better understand what spaghetti code is if you really make one.

If you're working on a commercial project or a company, you have to be careful. Any wrong decision can be costly. But if it is you personal project then it is okay. We can learn from other's experience and we can learn from our own mistakes.

Programmers dislike spaghetti code because it is hard to maintain. Finding and fixing bug is hard, adding new features is hard, even reading it is hard. Just as what Gus said, I believe there is a design flaw. But let's put that aside, here are the things you can do to minimize that bad effects.

Use proper names for variables, functions and procedures
It really will improve the code readability, a lot.

Put them into groups
Normally we should put the codes that related near together but you're going to separate it and put them into other unit. I heard you said 'a lot'. So those things should be grouped and properly arranged in a good order.

Don't mix with others
The unit that stores events, should not contain other kind of codes. If it has, you should move them out to another unit.

Give proper comments
Often, we need to revisit the code we wrote some years ago. It can be helpful if you document the code by using comments. Just don't overuse comment, that is bad too.

If someday that code becomes 'too hard' for you to handle then you will know it is a spaghetti code. Lesson learned. But if that never happens, you learn the new trick.

Gustavo 'Gus' Carreno

  • Hero Member
  • *****
  • Posts: 535
  • Professional amateur ;-P
Re: Setting events stored in other unit to controls
« Reply #9 on: May 10, 2021, 07:05:47 am »
Hey Gald,

After reading what Handoko wrote, and from a recent experience with code from a person that didn't went the OOP route and instead opted for the Procedural way and having units to group those procedure/function by his arbitrary rules, I now have another question:

How well versed are you on OOP?

I ask this because it kinda sounds like your decision to put Event handlers in other units is what that other fellah did with the procedural approach.

I need to stress this out: No shame what so ever.
But you have to pick a lane and stick to it.

And by that I mean, you either go OOP and every object has his own unit, of sorts.
Or you decide to go all in with the procedural approach and you spread your code in a different way.

If you embrace the OOP methodology, I think your code will be a lot kinder to other programmers.
If, on the other side, you are going for the procedural approach, then your code will be considered spaghetti by the majority of the programmers that only have patience for OOP.
But at least it's your spaghetti and you'll know how to navigate it. But, alas, you'll be a solo programmer on this one for a long time :(

So yeah, pick your lane, stick to it and PLEASE pay attention to the VERY GOOD advice that Handoko gave you, it's rather good and very valuable!!

Cheers,
Gus
Lazarus 2.1.0(trunk) FPC 3.3.1(trunk) Ubuntu 21.04 64b Dark Theme
Lazarus 2.0.12(stable) FPC 3.2.2(stable) Ubuntu 21.04 64b Dark Theme
http://github.com/gcarreno

Gald

  • New Member
  • *
  • Posts: 47
Re: Setting events stored in other unit to controls
« Reply #10 on: May 10, 2021, 08:32:21 am »
Thank you so so so much for your tips!

Handoko, I'll do some tests on it, and learn more about that.

Gus, I like your curiosity!
I'm doing an application with a kind of "web page" (scrollbox) that loads a file with the interface and his methods.
It's like what a Browser does with HTML, but with native controls. So, the users will have tools to create their own "pages", very limited, with a list of premade code in some units. If the user puts a Buttom he must choose a small list of premade actions, which will be stored in some units. Then he will generate his personal form (page) and it will be stored in a file and shared with others users to load it in runtime and navigate.
And was not a fan of OOP, but it starts to get interesting. I saw some things in recent years, but I didn't use my hands to write and learn for real. I gonna find some direct/concentrated articles/lessons about it right now.



You may find this video interest: https://www.youtube.com/watch?v=cvDyQUpaFf4
« Last Edit: May 10, 2021, 08:37:00 am by Gald »

Handoko

  • Hero Member
  • *****
  • Posts: 4285
  • My goal: build my own game engine using Lazarus
Re: Setting events stored in other unit to controls
« Reply #11 on: May 10, 2021, 08:40:41 pm »
What you're going to develop is not simple. Not only creating a set of predefined actions, you may also need to create a GUI editor and/or maybe a text parser/interpreter, which has some similarities with the game builder I'm developing. But I like your creativity and eagerness for doing something challenging.

Here I wrote a simplified demo. Not exactly what you want but it should give the idea.

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, Forms, ExtCtrls, StdCtrls, ActionsLib;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     btnUp: TButton;
  16.     btnDown: TButton;
  17.     btnLeft: TButton;
  18.     btnRight: TButton;
  19.     Shape1: TShape;
  20.     procedure FormCreate(Sender: TObject);
  21.   end;
  22.  
  23. var
  24.   Form1: TForm1;
  25.  
  26. implementation
  27.  
  28. {$R *.lfm}
  29.  
  30. { TForm1 }
  31.  
  32. procedure TForm1.FormCreate(Sender: TObject);
  33. begin
  34.   SetTarget(Shape1);
  35.   SetButtonUp(btnUp);
  36.   SetButtonDown(btnDown);
  37.   SetButtonLeft(btnLeft);
  38.   SetButtonRight(btnRight);
  39. end;
  40.  
  41. end.

Code: Pascal  [Select][+][-]
  1. unit ActionsLib;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, Forms, StdCtrls, ExtCtrls;
  9.  
  10. procedure SetTarget(Shape: TShape);
  11. procedure SetButtonUp(Button: TButton);
  12. procedure SetButtonDown(Button: TButton);
  13. procedure SetButtonLeft(Button: TButton);
  14. procedure SetButtonRight(Button: TButton);
  15.  
  16. implementation
  17.  
  18. type
  19.  
  20.   { TTmpButton }
  21.  
  22.   TTmpButton = class(TButton)
  23.   public
  24.     procedure ShapeMoveUp(Sender: TObject);
  25.     procedure ShapeMoveDown(Sender: TObject);
  26.     procedure ShapeMoveLeft(Sender: TObject);
  27.     procedure ShapeMoveRight(Sender: TObject);
  28.   end;
  29.  
  30. const
  31.   TargetObject: TShape = nil;
  32.  
  33. var
  34.   TmpButton: TTmpButton;
  35.  
  36. procedure SetTarget(Shape: TShape);
  37. begin
  38.   TargetObject := Shape;
  39. end;
  40.  
  41. procedure SetButtonUp(Button: TButton);
  42. begin
  43.   Button.OnClick := @TmpButton.ShapeMoveUp;
  44. end;
  45.  
  46. procedure SetButtonDown(Button: TButton);
  47. begin
  48.   Button.OnClick := @TmpButton.ShapeMoveDown;
  49. end;
  50.  
  51. procedure SetButtonLeft(Button: TButton);
  52. begin
  53.   Button.OnClick := @TmpButton.ShapeMoveLeft;
  54. end;
  55.  
  56. procedure SetButtonRight(Button: TButton);
  57. begin
  58.   Button.OnClick := @TmpButton.ShapeMoveRight;
  59. end;
  60.  
  61. procedure TTmpButton.ShapeMoveUp(Sender: TObject);
  62. begin
  63.   if not(Assigned(TargetObject)) then Exit;
  64.   TargetObject.Top := TargetObject.Top - 10;
  65.   if TargetObject.Top < -TargetObject.Height then
  66.     TargetObject.Top := TargetObject.Parent.Height;
  67. end;
  68.  
  69. procedure TTmpButton.ShapeMoveDown(Sender: TObject);
  70. begin
  71.   if not(Assigned(TargetObject)) then Exit;
  72.   TargetObject.Top := TargetObject.Top + 10;
  73.   if TargetObject.Top > TargetObject.Parent.Height then
  74.     TargetObject.Top := -TargetObject.Height;
  75. end;
  76.  
  77. procedure TTmpButton.ShapeMoveLeft(Sender: TObject);
  78. begin
  79.   if not(Assigned(TargetObject)) then Exit;
  80.   TargetObject.Left := TargetObject.Left - 10;
  81.   if TargetObject.Left < -TargetObject.Width then
  82.     TargetObject.Left := TargetObject.Parent.Width;
  83. end;
  84.  
  85. procedure TTmpButton.ShapeMoveRight(Sender: TObject);
  86. begin
  87.   if not(Assigned(TargetObject)) then Exit;
  88.   TargetObject.Left := TargetObject.Left + 10;
  89.   if TargetObject.Left > TargetObject.Parent.Width then
  90.     TargetObject.Left := -TargetObject.Width;
  91. end;
  92.  
  93. end.
« Last Edit: May 10, 2021, 08:42:42 pm by Handoko »

egsuh

  • Hero Member
  • *****
  • Posts: 739
Re: Setting events stored in other unit to controls
« Reply #12 on: May 11, 2021, 04:05:59 am »
Handoko's effort is remarkable. This would not be so difficult if actions are done to "Sender" itself, but  would be difficult if events have to do something on other controls.

Gald

  • New Member
  • *
  • Posts: 47
Re: Setting events stored in other unit to controls
« Reply #13 on: May 11, 2021, 04:25:41 am »
Handoko, your demo is impressive!
This was exactly what I need.

There are no words to express my gratitude for you.
Keep being the nice guy you are  :-*
« Last Edit: May 11, 2021, 04:29:34 am by Gald »

Gustavo 'Gus' Carreno

  • Hero Member
  • *****
  • Posts: 535
  • Professional amateur ;-P
Re: Setting events stored in other unit to controls
« Reply #14 on: May 11, 2021, 08:18:58 am »
Hey Gald,

Gus, I like your curiosity!

Thank you :)

I'm doing an application with a kind of "web page" (scrollbox) that loads a file with the interface and his methods.

Hummmm, so in a way, just what Lazarus is doing with the *.lfm. Rather interesting !!!

It's like what a Browser does with HTML, but with native controls. So, the users will have tools to create their own "pages", very limited, with a list of premade code in some units. If the user puts a Buttom he must choose a small list of premade actions, which will be stored in some units. Then he will generate his personal form (page) and it will be stored in a file and shared with others users to load it in runtime and navigate.
And was not a fan of OOP, but it starts to get interesting. I saw some things in recent years, but I didn't use my hands to write and learn for real. I gonna find some direct/concentrated articles/lessons about it right now.

Getting more interesting by the minute !!!
Please report back with your progress!!!

Can I ask if you're willing to share your code in one of the many code sharing platforms? I'm partial to GitHub, but anyone will do :)


You may find this video interest: https://www.youtube.com/watch?v=cvDyQUpaFf4

I'll have a watch :)

Cheers,
Gus
Lazarus 2.1.0(trunk) FPC 3.3.1(trunk) Ubuntu 21.04 64b Dark Theme
Lazarus 2.0.12(stable) FPC 3.2.2(stable) Ubuntu 21.04 64b Dark Theme
http://github.com/gcarreno

 

TinyPortal © 2005-2018