Recent

Author Topic: [SOLVED] Learning Procedural Type  (Read 5561 times)

tudi_x

  • Hero Member
  • *****
  • Posts: 532
[SOLVED] Learning Procedural Type
« on: November 11, 2017, 10:28:07 am »
hi All,
i started to learn procedural types as for the managing of several objects i would like to implement a simpler mechanism, something modeled in the below and attached.
basically from Button2 i would like to change the method on the click event for Button1 through a procedural approach and using an array of structures.
the below does not work but is there a way to make it work?
please advise.
thank you

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
  9.  
  10. type
  11.   TAction = procedure(AMessage: string) of object;
  12.  
  13. type
  14.   TStepInfo = record
  15.     Name: string;
  16.     Action: TAction;
  17.   end;
  18.  
  19. type
  20.   TSteps = array of TStepInfo;
  21.  
  22. type
  23.   TForm1 = class(TForm)
  24.     Button1: TButton;
  25.     Button2: TButton;
  26.     Memo1: TMemo;
  27.     procedure Button2Click(Sender: TObject);
  28.     procedure FormCreate(Sender: TObject);
  29.   private
  30.     s: TSteps;
  31.     step_id: word;
  32.     procedure Step1(AMessage: string);
  33.     procedure Step2(AMessage: string);
  34.   public
  35.  
  36.   end;
  37.  
  38. var
  39.   Form1: TForm1;
  40.  
  41. implementation
  42.  
  43. {$R *.lfm}
  44.  
  45. procedure TForm1.FormCreate(Sender: TObject);
  46. begin
  47.   step_id := 0;
  48.  
  49.   s[1].Name := 'msg1';
  50.   s[1].Action := Step1(s[1].Name); //unit1.pas(53,18) Error: Incompatible types: got "untyped" expected "<procedure variable type of procedure(AnsiString) of object;Register>"
  51.  
  52.   s[2].Name := 'msg2';
  53.   s[2].Action := Step2(s[2].Name);
  54. end;
  55.  
  56. procedure TForm1.Button2Click(Sender: TObject);
  57. begin
  58.   step_id := step_id + 1;
  59.   Button1.OnClick := @s[step_id].Action; //unit1.pas(62,22) Error: Incompatible types: got "Pointer" expected "<procedure variable type of procedure(TObject) of object;Register>"
  60. end;
  61.  
  62. procedure TForm1.Step1(AMessage: string);
  63. begin
  64.   Memo1.Append('step 1: ' + AMessage);
  65. end;
  66.  
  67. procedure TForm1.Step2(AMessage: string);
  68. begin
  69.   Memo1.Append('step 2: ' + AMessage);
  70. end;
  71.  
  72. end.
« Last Edit: November 11, 2017, 05:08:34 pm by tudi_x »
Lazarus 2.0.2 64b on Debian LXDE 10

Eugene Loza

  • Hero Member
  • *****
  • Posts: 673
    • My games in Pascal
Re: Learning Procedural Type
« Reply #1 on: November 11, 2017, 11:40:24 am »
First of all, you have to provide a reference (pointer) to the procedural type.
i.e. not
s[1].Action := Step1(s[1].Name);
but
s[1].Action := @Step1;
(note the "@" symbol which means that @Step1 is a pointer/reference to Step1).

As you've also noticed you can't pass parameters to a pointer.
E.g.
Code: Pascal  [Select][+][-]
  1. type TProcedure = procedure(a: integer);
  2. Proc: TProcedure;
  3.  
  4. procedure MyProc(a: integer);
  5. begin
  6.   writeln(a);
  7. end;
  8.  
  9. ...
  10.  
  11. Proc := @MyProc; //assign a procedural variable;
  12.  
  13. Proc(a); //Call the assigned procedure with the parameter specified.
« Last Edit: November 11, 2017, 11:46:41 am by Eugene Loza »
My FOSS games in FreePascal&CastleGameEngine: https://decoherence.itch.io/ (Sources: https://gitlab.com/EugeneLoza)

Eugene Loza

  • Hero Member
  • *****
  • Posts: 673
    • My games in Pascal
Re: Learning Procedural Type
« Reply #2 on: November 11, 2017, 11:46:00 am »
The second procedure:
Button1.OnClick := @s[step_id].Action
You also can't assign OnClick which is procedure(Sender: TObject) of object to procedure(AMessage: string) of object - they have different parameter - TObject in the first case and String in the second. As far as you don't want to change Lazarus source code to change the OnClick definition, you have to provide it with a valid procedure(Sender: TObject) of object procedure reference.
P.S. you don't need the @ symbol here, as Action is TAction which is already a reference and "reference to a reference" will not work as expected.
My FOSS games in FreePascal&CastleGameEngine: https://decoherence.itch.io/ (Sources: https://gitlab.com/EugeneLoza)

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: Learning Procedural Type
« Reply #3 on: November 11, 2017, 11:49:48 am »
It seems there is also another misunderstanding from tudi_x.

The onCLick event from a tbutton has the following declaration:
Code: [Select]
public property TControl.OnClick: TNotifyEvent  read FOnClick  write FOnClick  stored IsOnClickStored;

So, looking at TNotifyEvent that reads:
Code: [Select]
type TNotifyEvent = procedure(Sender: TObject) of object

And alas that does not match:
Code: [Select]
type
  TAction = procedure(AMessage: string) of object;

So that the assignment:
Code: [Select]
  Button1.OnClick := @s[step_id].Action;
Wil fail as the two declarations differ.

edit: Ah, beaten by Eugene Loza  :)
« Last Edit: November 11, 2017, 11:52:15 am by molly »

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Learning Procedural Type
« Reply #4 on: November 11, 2017, 12:21:22 pm »
Also note that dynamic arrays require a SetLength() before use, and are indexed from zero (not 1).
Try the attached project.

tudi_x

  • Hero Member
  • *****
  • Posts: 532
Re: Learning Procedural Type
« Reply #5 on: November 11, 2017, 05:07:42 pm »
thank you guys!
changed the code to:

Code: Pascal  [Select][+][-]
  1. unit main;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  9.   Buttons, typinfo;
  10.  
  11. type
  12.   TStepsEnum = (the_step0, the_step1, the_step2);
  13.  
  14. type
  15.   TAction = procedure(ASender: TObject) of object;
  16.  
  17. type
  18.   TStepInfo = record
  19.     Name: string;
  20.     Action: TAction;
  21.   end;
  22.  
  23. type
  24.   TSteps = array of TStepInfo;
  25.  
  26. type
  27.   TForm1 = class(TForm)
  28.     BitBtn1: TBitBtn;
  29.     Button1: TButton;
  30.     Button2: TButton;
  31.     Memo1: TMemo;
  32.     procedure BitBtn1Click(Sender: TObject);
  33.     procedure Button2Click(Sender: TObject);
  34.     procedure FormCreate(Sender: TObject);
  35.   private
  36.     s: TSteps;
  37.     step_id: word;
  38.     procedure Step0(ASender: TObject);
  39.     procedure Step1(ASender: TObject);
  40.     procedure Step2(ASender: TObject);
  41.   public
  42.  
  43.   end;
  44.  
  45. var
  46.   Form1: TForm1;
  47.  
  48. implementation
  49.  
  50. {$R *.lfm}
  51.  
  52. procedure TForm1.FormCreate(Sender: TObject);
  53. begin
  54.   step_id := 0;
  55.   SetLength(s, Ord(High(TStepsEnum)) + 1);
  56.  
  57.   s[0].Name := GetEnumName(TypeInfo(TStepsEnum), Ord(0));
  58.   s[0].Action := @Step0;
  59.  
  60.   s[1].Name := GetEnumName(TypeInfo(TStepsEnum), Ord(1));
  61.   s[1].Action := @Step1;
  62.  
  63.   s[2].Name := GetEnumName(TypeInfo(TStepsEnum), Ord(2));
  64.   s[2].Action := @Step2;
  65. end;
  66.  
  67. procedure TForm1.Button2Click(Sender: TObject);
  68. begin
  69.   Button1.OnClick := s[step_id].Action;
  70. end;
  71.  
  72. procedure TForm1.BitBtn1Click(Sender: TObject);
  73. begin
  74.   step_id := step_id + 1;
  75. end;
  76.  
  77. procedure TForm1.Step0(ASender: TObject);
  78. begin
  79.   Memo1.Append('id: ' + IntToStr(step_id) + 'step 0: ' + s[step_id].Name);
  80. end;
  81.  
  82. procedure TForm1.Step1(ASender: TObject);
  83. begin
  84.   Memo1.Append('step 1: ' + s[step_id].Name);
  85. end;
  86.  
  87. procedure TForm1.Step2(ASender: TObject);
  88. begin
  89.   Memo1.Append('step 2: ' + s[step_id].Name);
  90. end;
  91.  
  92. end.
Lazarus 2.0.2 64b on Debian LXDE 10

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: [SOLVED] Learning Procedural Type
« Reply #6 on: November 11, 2017, 06:21:00 pm »
You seem to have got the idea!

Note that High(array) returns an ordinal number, so does not need Ord(). Also, "type" can introduce a series of type definitions, so does not need to be repeated.

 

TinyPortal © 2005-2018