Recent

Author Topic: Making an object self-contained  (Read 713 times)

Davo

  • Full Member
  • ***
  • Posts: 131
Making an object self-contained
« on: July 13, 2020, 06:21:02 am »
My project contains an object for a lightswitch that holds two images – one showing the switch in the up position and the other in the down position. It is important that the consequence of the OnClick event for each image can be acted upon by a function in the form that instantiates the object. The current coding of the object works just fine but it is unsatisfactory in that the object is not completely self contained as I believe it should be. The problems are :

1. The parent property of the two images needs to be assigned to the instantiating form before the images can be displayed on that form. To that end, the object's constructor relies on a parameter that identifies that form. It would be much better if the object itself could identify which form has instantiated it and so do away with the need for the parameter. Something like “parent := GetParent”. Can that be done?

2. The two images' common OnClick procedure currently makes a direct call to a procedure in the instantiating form by specifically naming both that form and the procedure - “frmSwitches.flipSwitch”. This procedure handles the business consequences of the OnClick event. There are two issues here :

(a) Although the object's constructor assigns the instantiating form's identity to an object property named ParentForm, using “ParentForm.flipSwitch” does not compile giving the error “identifier idents no member “flipSwitch”. Can that be fixed?

(b) Specifically naming the Form procedure flipSwitch is ugly! It would be much better if the OnClick procedure could somehow trigger a standard notification that could be picked up by the Form and translated there into meaning a call to flipSwitch. Or is that just wishful thinking?

A relevant abstract from the current code is :

Code: Pascal  [Select][+][-]
  1. interface
  2.  
  3. type
  4.  
  5. TMySwitch = class
  6.   ParentForm : TForm;
  7.   SwitchUp : TImage;
  8.   SwitchDown : TImage;
  9.   ...
  10.   constructor Init(useForm:TForm);
  11.   procedure SwitchClick(Sender:TObject);
  12.   ...
  13. end;
  14.  
  15. TfrmSwitches = class(TForm)
  16.   ....
  17.   procedure FormCreate(Sender: TObject);
  18.   procedure flipSwitch;
  19.   ....
  20. end;
  21.  
  22. var
  23.   frmSwitches: TfrmSwitches;
  24.   MySwitch : TMySwitch;
  25.  
  26. implementation
  27.  
  28. constructor TMySwitch.Init(useForm:TForm);
  29. begin
  30.   inherited;
  31.   ParentForm := useForm;
  32.   SwitchUp := TImage.create (ParentForm);
  33.   with SwitchUp do
  34.     begin
  35.       inherited;
  36.       picture.LoadFromFile('Brown_switch_up.jpg');
  37.       parent := ParentForm;
  38.       onClick := @SwitchClick;
  39.    end;
  40.   SwitchDown := TImage.create (ParentForm);
  41.   with SwitchDown do
  42.     begin
  43.       inherited;
  44.       picture.LoadFromFile('Brown_switch_Down.jpg');
  45.       parent := ParentForm;
  46.       onClick := @SwitchClick;
  47.    end;
  48. end;
  49.  
  50. procedure TMySwitch.SwitchClick(Sender:TObject);
  51. begin
  52.   flip;
  53.   frmSwitches.flipSwitch;  // THIS COMPILES OK
  54. //  ParentForm.flipSwitch;    THIS DOES NOT COMPILE
  55. end;
  56.  
  57. procedure TfrmSwitches.FormCreate(Sender: TObject);
  58. begin
  59.   MySwitch := TMySwitch.init(Self);
  60.   ...
  61. end;
  62.  
  63. procedure TfrmSwitches.flipSwitch;
  64. begin
  65.   ...
  66. end;
  67. end.

Lazarus version 1.6
FPC version 3.0.0
« Last Edit: July 13, 2020, 06:23:12 am by Davo »

Handoko

  • Hero Member
  • *****
  • Posts: 3640
  • My goal: build my own game engine using Lazarus
Re: Making an object self-contained
« Reply #1 on: July 13, 2020, 03:39:41 pm »
1. The parent property of the two images needs to be assigned to the instantiating form before the images can be displayed on that form. To that end, the object's constructor relies on a parameter that identifies that form. It would be much better if the object itself could identify which form has instantiated it and so do away with the need for the parameter. Something like “parent := GetParent”. Can that be done?

I don't think it is possible, you have to manually set to which form you want it associated with. Unless your program only have 1 form, then you can use Application.MainForm.

(b) Specifically naming the Form procedure flipSwitch is ugly! It would be much better if the OnClick procedure could somehow trigger a standard notification that could be picked up by the Form and translated there into meaning a call to flipSwitch. Or is that just wishful thinking?

If I understood your post correctly, you could put this on TMySwitch.Init:
Code: Pascal  [Select][+][-]
  1.   ParentForm.OnClick := @CustomFormClick;

Because the CustomFormClick procedure is in TMySwitch, you can put your code to do whatever you want including calling flipSwitch. So, for the problem (a), will be not needed.
« Last Edit: July 13, 2020, 04:15:10 pm by Handoko »

Cyrax

  • Hero Member
  • *****
  • Posts: 829
Re: Making an object self-contained
« Reply #2 on: July 13, 2020, 03:45:49 pm »
Code: Pascal  [Select][+][-]
  1. constructor TMySwitch.Init(useForm:TForm);
  2. begin
  3.   inherited;
  4.   ParentForm := useForm;
  5.   SwitchUp := TImage.create (ParentForm);
  6.   with SwitchUp do
  7.     begin
  8.       inherited;
  9.       picture.LoadFromFile('Brown_switch_up.jpg');
  10.       parent := ParentForm;
  11.       onClick := @SwitchClick;
  12.    end;
  13.   SwitchDown := TImage.create (ParentForm);
  14.   with SwitchDown do
  15.     begin
  16.       inherited;
  17.       picture.LoadFromFile('Brown_switch_Down.jpg');
  18.       parent := ParentForm;
  19.       onClick := @SwitchClick;
  20.    end;
  21. end;

You should rename your class constructor to Create instead of Init. Also why are you calling inherited multiple times in your constructor code? It doesn't seem to logical to me.

PascalDragon

  • Hero Member
  • *****
  • Posts: 1941
  • Compiler Developer
Re: Making an object self-contained
« Reply #3 on: July 13, 2020, 03:55:08 pm »
My project contains an object for a lightswitch that holds two images – one showing the switch in the up position and the other in the down position. It is important that the consequence of the OnClick event for each image can be acted upon by a function in the form that instantiates the object. The current coding of the object works just fine but it is unsatisfactory in that the object is not completely self contained as I believe it should be.

Why don't you create your own component that contains the two images and provides an event each for the two images (e.g. OnTopClick and OnBottomClick) that the form can then use?

Davo

  • Full Member
  • ***
  • Posts: 131
Re: Making an object self-contained
« Reply #4 on: July 14, 2020, 05:04:16 am »
Thank you Handoko, Cyrax and PascalDragon for your replies, all of which are much appreciated.

Handoko

Quote
I don't think it is possible, you have to manually set to which form you want it associated with.

That's a pity.

Quote
Unless your program only have 1 form, then you can use Application.MainForm.


Unfortunately the project has 3 forms and, as you have implied, using Application.MainForm doesn't work.

Quote
If I understood your post correctly, you could put this on TMySwitch.Init :
    ParentForm.OnClick := @CustomFormClick;
Because the CustomFormClick procedure is in TMySwitch, you can put your code to do whatever you want including calling flipSwitch.

I probably did not make my question clear enough. What I would like to do is :
    (a) avoid hard-coding the parent form's name “frmSwitches”, and
    (b) avoid hard-coding the Parent form's procedure name “flipSwitch”.
in the Object images' OnClick procedure that is named “SwitchClick”.

As regards (a) I had thought that since ParentForm has already been defined by the Object's constructor I should be able to use it instead of “frmSwitches” - but I was wrong. As regards (b) – I was hoping that SwitchClick might be able to generate some form of standard notification along the lines of "Hey! I've got a message for you." that could be intercepted by the application and then translated by the parent form into a call to its procedure flipSwitch. Maybe just wishful thinking but if it is possible I'm still in the dark.

The result of inserting ParentForm.OnClick := @SwitchClick into the constructor simply has the result that when the parent  form is clicked the switch image is then displayed but the call to the application's business rules contained in the procedure flipSwitch is still hard-coded in SwitchClick.

Cyrax

Quote
… calling inherited multiple times in your constructor code ... doesn't seem to logical ....

I agree and the superfluous two calls have now been removed.

PascalDragon

Quote
Why don't you create your own component that contains the two images and provides an event each for the two images (e.g. OnTopClick and OnBottomClick) that the form can then use?

Creating a component is something that I have not yet tried and is probably something I should do. But I wonder if it would solve my problem?

For the sake of brevity, when framing my question I did not include reference to methods contained in the Object such as Flip, TurnUp, TurnDown and HideBothImages which do pretty much as their names suggest. Through these the parent form can have direct control over the appearance and status of the switch. (In fact, the parent form actually instantiates more than one switch but that is not relevant here.) For the moment I don't see how these methods can be handled in the case of a new component.

GetMem

  • Hero Member
  • *****
  • Posts: 3752
Re: Making an object self-contained
« Reply #5 on: July 14, 2020, 07:00:27 am »
Passing the form as parameter to the constructor of TMySwitch it's a perfectly valid solution.

Quote
(a) avoid hard-coding the parent form's name “frmSwitches”, and
Code: Pascal  [Select][+][-]
  1. TfrmSwitches(ParentForm).flipSwitch;

Quote
(b) avoid hard-coding the Parent form's procedure name “flipSwitch”.
in the Object images' OnClick procedure that is named “SwitchClick”.
I'm not sure what exactly are you trying to achieve, maybe something like this?
Code: Pascal  [Select][+][-]
  1. type
  2.   TOnSwitch = procedure(Sender: TObject; AOnOff: Integer) of object;
  3.   TMySwitch = class
  4.   private
  5.     FParentForm: TForm;
  6.     FSwitchUp: TImage;
  7.     FSwitchDown: TImage;
  8.     FOnSwitch: TOnSwitch;
  9.     FOnOff: Integer;
  10.   private
  11.     procedure DoOnClick(Sender: TObject);
  12.   public
  13.     constructor Create(AParentForm: TForm);
  14.   public
  15.     property OnSwitch: TOnSwitch read FOnSwitch write FOnSwitch;
  16.    end;
  17.  
  18.   TfrmSwitches = class(TForm)
  19.   private
  20.     procedure DoOnSwitch(Sender: TObject; AOnOff: Integer);
  21.   public
  22.     procedure FormCreate(Sender: TObject);
  23.     procedure FormDestroy(Sender: TObject);  
  24.   end;
  25.  
  26. var
  27.   frmSwitches: TfrmSwitches;
  28.   MySwitch : TMySwitch;
  29.  
  30. implementation
  31.  
  32. constructor TMySwitch.Create(AParentForm: TForm);
  33. begin
  34.   FParentForm := AParentForm;
  35.   FSwitchUp := TImage.create(FParentForm);
  36.   with FSwitchUp do
  37.   begin
  38.     Picture.LoadFromFile('Brown_switch_up.jpg');
  39.     Parent := FParentForm;
  40.     Tag := 1;
  41.     OnClick := @DoOnClick;
  42.   end;
  43.   FSwitchDown := TImage.Create(FParentForm);
  44.   with FSwitchDown do
  45.   begin
  46.     Picture.LoadFromFile('Brown_switch_Down.jpg');
  47.     Parent := FParentForm;
  48.     Tag := 0;
  49.     OnClick := @DoOnClick;
  50.   end;
  51. end;
  52.  
  53. procedure TMySwitch.DoOnClick(Sender: TObject);
  54. begin
  55.   FOnOff := (Sender as TImage).Tag;
  56.   //more code here
  57.   if Assigned(FOnSwitch) then
  58.     FOnSwitch(Self, FOnOff);
  59. end;
  60.  
  61. //------------------------------------------------------------------
  62. procedure TfrmSwitches.FormCreate(Sender: TObject);
  63. begin
  64.   MySwitch := TMySwitch.Create(Self);
  65.   MySwitch.OnSwitch := @DoOnSwitch;
  66. end;
  67.  
  68. procedure TfrmSwitches.FormDestroy(Sender: TObject);
  69. begin
  70.   MySwitch.Free;
  71. end;  
  72.  
  73. procedure TfrmSwitches.DoOnSwitch(Sender: TObject; AOnOff: Integer);
  74. begin
  75.   case AOnOff of
  76.     0: ShowMessage('light is off');
  77.     1: ShowMessage('light is on');
  78.   end;
  79. end;
« Last Edit: July 14, 2020, 07:35:02 am by GetMem »

Handoko

  • Hero Member
  • *****
  • Posts: 3640
  • My goal: build my own game engine using Lazarus
Re: Making an object self-contained
« Reply #6 on: July 14, 2020, 08:21:29 am »
This is my proposal:

Code: Pascal  [Select][+][-]
  1. unit uniSwitch;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, ExtCtrls, Forms;
  9.  
  10. type
  11.  
  12.   { TMySwitch }
  13.  
  14.   TMySwitch = class
  15.   private
  16.     FParentForm:   TForm;
  17.     FSwitchUp:     TImage;
  18.     FSwitchDown:   TImage;
  19.     FSwitchState:  Boolean;
  20.     FCallBack:     TNotifyEvent;
  21.     procedure SwitchClick(Sender: TObject);
  22.   public
  23.     constructor Create(Form: TForm);
  24.     procedure SetCallBack(aNotifyEvent: TNotifyEvent);
  25.     procedure Flip;
  26.     property State: Boolean read FSwitchState;
  27.   end;
  28.  
  29. implementation
  30.  
  31. { TMySwitch }
  32.  
  33. procedure TMySwitch.SwitchClick(Sender: TObject);
  34. begin
  35.   FSwitchState        := not(FSwitchState);
  36.   FSwitchUp.Visible   := FSwitchState;
  37.   FSwitchDown.Visible := not(FSwitchState);
  38.   if Assigned(FCallBack) then
  39.     FCallBack(Sender);
  40. end;
  41.  
  42. constructor TMySwitch.Create(Form: TForm);
  43. begin
  44.   FParentForm  := Form;
  45.   FSwitchState := False;
  46.   FSwitchUp    := TImage.Create(FParentForm);
  47.   FSwitchDown  := TImage.Create(FParentForm);
  48.   with FSwitchDown do
  49.   begin
  50.     Picture.LoadFromFile('imgOff.jpg');
  51.     Parent  := FParentForm;
  52.     Left    := 20;
  53.     Top     := 20;
  54.     Visible := False;
  55.     OnClick := @SwitchClick;
  56.   end;
  57.   with FSwitchUp do
  58.   begin
  59.     Picture.LoadFromFile('imgOn.jpg');
  60.     Parent  := FParentForm;
  61.     Left    := 20;
  62.     Top     := 20;
  63.     Visible := False;
  64.     OnClick := @SwitchClick;
  65.   end;
  66.   SwitchClick(Self);
  67. end;
  68.  
  69. procedure TMySwitch.SetCallBack(aNotifyEvent: TNotifyEvent);
  70. begin
  71.   FCallBack := aNotifyEvent;
  72. end;
  73.  
  74. procedure TMySwitch.Flip;
  75. begin
  76.   SwitchClick(Self);
  77. end;
  78.  
  79. end.

mangakissa

  • Hero Member
  • *****
  • Posts: 1086
Re: Making an object self-contained
« Reply #7 on: July 14, 2020, 08:26:13 am »
Why loading everytime if you can put it once in TImage and use it when needed.
Lazarus 2.06 (64b) / FPC 3.0.4 / Windows 10
stucked on Delphi 10.3.1

Handoko

  • Hero Member
  • *****
  • Posts: 3640
  • My goal: build my own game engine using Lazarus
Re: Making an object self-contained
« Reply #8 on: July 14, 2020, 08:31:07 am »
Yea, you found it. Not too good practice.

I did think about it. But I just want to make the code simpler so can be easy to understand. Of course if the code was for my own usage, I will load the images once only.

PascalDragon

  • Hero Member
  • *****
  • Posts: 1941
  • Compiler Developer
Re: Making an object self-contained
« Reply #9 on: July 14, 2020, 09:21:04 am »
Quote
Why don't you create your own component that contains the two images and provides an event each for the two images (e.g. OnTopClick and OnBottomClick) that the form can then use?

Creating a component is something that I have not yet tried and is probably something I should do. But I wonder if it would solve my problem?

For the sake of brevity, when framing my question I did not include reference to methods contained in the Object such as Flip, TurnUp, TurnDown and HideBothImages which do pretty much as their names suggest. Through these the parent form can have direct control over the appearance and status of the switch. (In fact, the parent form actually instantiates more than one switch but that is not relevant here.) For the moment I don't see how these methods can be handled in the case of a new component.

That definitely sounds like something that deserves its own component. Here I have a skeleton for you to get you started (not tested):

Code: Pascal  [Select][+][-]
  1. type
  2.   // possible alternatives are TGraphicControl and TWinControl
  3.   TSwitch = class(TCustomControl)
  4.   private
  5.     fImageTop: TImage;
  6.     fImageBottom: TImage;
  7.   public
  8.     // inside the constructor you create the image instances
  9.     // and arrange them correctly inside this component;
  10.     // you set their Parent property to this
  11.     constructor Create(aOwner: TComponent);
  12.     procedure Flip;
  13.     procedure TurnUp;
  14.     procedure TurnDown;
  15.     // this could be done with a property as well (or two)
  16.     procedure HideBothImages;
  17.   published
  18.     property ImageTop: TImage read fImageTop;
  19.     property ImageBottom: TImage read fImageBottom;
  20.   end;

As a first step you instantiate your component at runtime, but once it works you can also move it to its own package, install the package and drop it on the form like any other component.

For further information you can also take a look here.

Davo

  • Full Member
  • ***
  • Posts: 131
Re: Making an object self-contained
« Reply #10 on: July 15, 2020, 08:54:48 am »
GetMem, Handoko (Edit - include GetMem. Apologies for earlier oversight)

You have gone to a lot of trouble on my behalf for which I thank you most sincerely.

I has taken me a while to digest how the required code elements fit together but I seem to have got there in the end. The object's OnClick event now successfully calls the procedure in the parent form that implements the necessary business rules. 

Should anyone who has been following this thread and who like me was puzzled about how to call an outside procedure from within an object's event handler - here is the running code as it now stands (I have commented the relevant  lines with (* *** *) :
Code: Pascal  [Select][+][-]
  1. type
  2.   TOnSwitch = procedure(Sender: TObject; ID : integer) of object;  (* *** *)
  3.  
  4.   TMySwitch = class
  5.     type
  6.       CountryOrientation = (OnIsUp, OnIsDown);
  7.     var
  8.     {private}
  9.     parentForm : TForm;
  10.     num : integer;        
  11.     imgUp : TImage;      
  12.     imgDown : TImage;      
  13.     Up : boolean;          
  14.     Onn : boolean;
  15.     Orientation : CountryOrientation;
  16.     FOnSwitch: TOnSwitch;                              (* *** *)
  17.     procedure SwitchClick(Sender:TObject);
  18.     {public}
  19.     constructor Init(useForm:TForm);
  20.     destructor Zero;
  21.     property OnSwitch: TOnSwitch read FOnSwitch write FOnSwitch;   (* *** *)
  22.     procedure flip;
  23.     procedure turnUp;
  24.     procedure turnDown;
  25.     procedure hideBothSwitches;
  26.     procedure Play;
  27.     procedure setPos(L,T:integer);
  28.     procedure setSize(W,H:integer);
  29.     procedure setOrientation(input:CountryOrientation);
  30.   end;
  31.  
  32.   { TfrmSwitches }
  33.  
  34.   TfrmSwitches = class(TForm)
  35.     {GUI routines}
  36.     procedure FormCreate(Sender: TObject);
  37.     procedure FormDestroy(Sender: TObject);
  38.   private
  39.     { private declarations }
  40.     {GUI routines}
  41.     procedure initialiseSwitches;
  42.     {Switch operating routines}
  43.     procedure DoOnSwitch(Sender: TObject;ID : Integer);    (* *** *)
  44.     procedure flipSwitch(swNum:integer);
  45.   public
  46.     { public declarations }
  47.   end;
  48.  
  49. var
  50.   frmSwitches: TfrmSwitches;
  51.   Sw : array [1..4] of TMySwitch; // holds the 4 switch objects
  52.  
  53. implementation
  54.  
  55. {$R *.lfm}
  56.  
  57. (* ... Switch handling ..................................... *)
  58.  
  59. {TMySwitch}
  60.  
  61. constructor TMySwitch.Init(useForm:TForm);
  62.  
  63.   procedure setVariables(var thisImage:TImage);
  64.   begin
  65.     with thisImage do
  66.       begin
  67.         parent := ParentForm;
  68.         stretch := true;
  69.         onClick := @SwitchClick;    (* *** *)
  70.       end;
  71.   end;
  72.  
  73. begin
  74.   inherited;
  75.   ParentForm := useForm;
  76.   imgUp := TImage.create (ParentForm);
  77.   imgDown := TImage.create (ParentForm);
  78.   imgUp.picture.LoadFromFile('Brown_switch_up.jpg');
  79.   setVariables(imgUp);
  80.   imgDown.picture.LoadFromFile('Brown_switch_down.jpg');
  81.   setVariables(imgDown);
  82.   Up := false;
  83. end;
  84.  
  85. destructor TMySwitch.Zero;
  86. begin
  87.   inherited;
  88.   imgUp.free;
  89.   imgDown.free;
  90. end;
  91.  
  92. procedure TMySwitch.setPos(L,T:integer);
  93. begin
  94.   imgUp.left := L;
  95.   imgUp.top := T;
  96.   imgDown.left := imgUp.left;
  97.   imgDown.top := imgUp.top;
  98. end;
  99.  
  100. procedure TMySwitch.setSize(W,H:integer);
  101. begin
  102.   imgUp.width := W;
  103.   imgUp.height := H;
  104.   imgDown.width := imgUp.width;
  105.   imgDown.Height := imgUp.height;
  106. end;
  107.  
  108. Procedure TMySwitch.flip;
  109. begin
  110.   Up := not Up;
  111.   if Up then
  112.     begin
  113.       imgUp.show;
  114.       imgDown.hide;
  115.       onn := (orientation = OnIsUp);
  116.     end
  117.   else
  118.     begin
  119.       imgUp.hide;
  120.       imgDown.show;
  121.       onn := (orientation = OnIsDown);
  122.     end;
  123. end;
  124.  
  125. procedure TMySwitch.Play;
  126. begin
  127.   PlaySound('light-switch-click.wav',0,SND_ASYNC);
  128. end;
  129.  
  130. procedure TMySwitch.SwitchClick(Sender:TObject);
  131. {reverses the switch position and activates the test to see if the light bulb's
  132.  lit status should be changed}
  133. begin
  134.   Play;
  135.   flip;
  136.   if Assigned(FOnSwitch) then    (* *** *)
  137.     FOnSwitch(Self,num);             (* *** *)
  138. end;
  139.  
  140. procedure TMySwitch.turnUp;
  141. {forces the switch to the up position}
  142. begin
  143.   imgUp.Show;
  144.   imgDown.Hide;
  145.   Up := true;
  146.   onn := (orientation = OnIsUp);
  147. end;
  148.  
  149. procedure TMySwitch.turnDown;
  150. {forces the switch to the down position}
  151. begin
  152.   imgUp.Hide;
  153.   imgDown.Show;
  154.   Up := false;
  155.   onn := (orientation = OnIsDown);
  156. end;
  157.  
  158. procedure TMySwitch.hideBothSwitches;
  159. begin
  160.   imgUp.Hide;
  161.   imgDown.Hide;
  162. end;
  163.  
  164. procedure TMySwitch.setOrientation(input:CountryOrientation);
  165. {input is provided via the OnClick event of a two-button
  166.   radio group on the parent form}
  167. begin
  168.   orientation := input;
  169. end;
  170.  
  171. { TfrmSwitches }
  172.  
  173. (* ... GUI ROUTINES ........................................................ *)
  174.  
  175. procedure TfrmSwitches.FormCreate(Sender: TObject);
  176. {initialises the variables used}
  177. begin
  178.   initialiseSwitches;
  179.   ...
  180. end;
  181.  
  182. procedure TfrmSwitches.initialiseSwitches;
  183. {create the 4 switch objects and locate their up and down images across the
  184.  form}
  185. var i, lft : integer;
  186. begin
  187.   for i := 1 to 4 do
  188.     begin
  189.       Sw[i] := TMySwitch.init(Self);
  190.       with Sw[i] do
  191.       begin
  192.         case i of
  193.           1 : lft := 49;
  194.           2 : lft := 97;
  195.           3 : lft := 145;
  196.           4 : lft := 193;
  197.         end;
  198.         setPos(lft,143);
  199.         setSize(33,66);
  200.         num := i;
  201.         OnSwitch := @DoOnSwitch;     (* *** *)                              
  202.         flip;
  203.       end;
  204.     end;
  205. end;
  206.  
  207. procedure TfrmSwitches.FormDestroy(Sender: TObject);
  208. var i : integer;
  209. begin
  210.   for i := 1 to 4 do Sw[i].Zero;
  211. end;
  212.  
  213. (* ... SWITCH OPERATING ROUTINES ............................................ *)
  214.  
  215. procedure TfrmSwitches.DoOnSwitch(Sender:TObject;ID:integer);    (* *** *)
  216. begin
  217.   flipSwitch(ID);
  218. end;
  219.  
  220. procedure TfrmSwitches.flipSwitch(swNum:integer);
  221. begin
  222.   ...
  223. end;
  224.  

PascalDragon

Since the immediate coding problem has been solved, now is a good time to see about creating a component. I'll have to give it a go. Thank you for the code skeleton. It will be a big help.
« Last Edit: July 16, 2020, 06:35:05 pm by Davo »

Davo

  • Full Member
  • ***
  • Posts: 131
Re: Making an object self-contained
« Reply #11 on: July 16, 2020, 08:40:29 am »
I find that in order to better understand and remember a complicated coding matter it's useful to document the steps needed to accomplish it and include an explanation of the purpose of each step. It also helps if the matter can be visualised in a graphic. These I have done, committing them to a .pdf document. It may be that someone else might find them useful. A copy of the .pdf is attached.

Of course, getting feedback on any errors noted in the .pdf would be much appreciated.

Handoko

  • Hero Member
  • *****
  • Posts: 3640
  • My goal: build my own game engine using Lazarus
Re: Making an object self-contained
« Reply #12 on: July 16, 2020, 03:37:46 pm »
Thank you for sharing us the document explaining how to do it. The thing you were doing is tricky, the explanation will be very useful for someone.

 

TinyPortal © 2005-2018