Recent

Author Topic: [SOLVED] TImage TmouseEvent stackframe issue  (Read 2202 times)

4nlegion

  • New member
  • *
  • Posts: 8
[SOLVED] TImage TmouseEvent stackframe issue
« on: August 03, 2021, 05:03:16 am »
Hi, i have a problem with the stackframe of the OnMouseDown event of a TImage created at runtime. Note the Timage.OnMouseDown assignment via TMethod.
Upon MouseDown, MouseDownEvent is called with the wrong stackframe. It appears to be off by sizeof(TMouseButton). Is my definition of TMouseEvent incorrect? Regards.
Also, is there a recommended practice to preclude such a declaration mismatch?

Details: Ubuntu 20.04, FPC version 3.2.0 [2020/07/07] for x86_64, Lazarus: 2.0.12

Code: Pascal  [Select][+][-]
  1. procedure MouseDownEvent(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X,Y: Integer);
  2. begin
  3.         if not (Sender is TImage) then exit;
  4.         Form1.ListBox1.Items.AddText(format('[x,y]: [%d,%d]',[x,y]));   // note incorrect [x,y] reporting
  5. end;
  6.  
  7. procedure TForm1.FormCreate(Sender: TObject);
  8. var
  9.         e:      TMethod;
  10. begin
  11.         img:=TImage.create(Form1);
  12.         img.Parent:=Form1;
  13.         img.left:=32;
  14.         img.top:=32;
  15.         img.width:=400;
  16.         img.height:=400;
  17.         img.Canvas.Brush.Color := clgreen;
  18.         img.Canvas.Brush.style := bsSolid;
  19.         img.canvas.FillRect(0,0,400,400);
  20.  
  21.         e.Data:=img;
  22.         e.Code:=@MouseDownEvent;
  23.         img.OnMouseDown:=TMouseEvent(e);
  24. end;
  25.  
« Last Edit: August 03, 2021, 06:52:31 am by 4nlegion »

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: TImage TmouseEvent stackframe issue
« Reply #1 on: August 03, 2021, 06:10:32 am »
No, it isn't. Events are declared as "of object" which means that they have to be declared/defined as methods of an object (usually, though not always, of the form itself). Try something like:
Code: Pascal  [Select][+][-]
  1. {in the interface section ...}
  2.  
  3.   TForm1 = class(TForm)
  4.     {... other declarations ...}
  5.     procedure ImageMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X,Y: Integer);
  6.   end;
  7.  
  8. {then, in the implementation section ...}
  9.  
  10. procedure TForm1.ImageMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X,Y: Integer);
  11. begin
  12.         if not (Sender is TImage) then exit;
  13.         Form1.ListBox1.Items.AddText(format('[x,y]: [%d,%d]',[x,y]));   // note incorrect [x,y] reporting
  14. end;

Any reason why you're using an assignment through TMethod? Normally that's used only when you need to access the RTTI of an object's methods.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

4nlegion

  • New member
  • *
  • Posts: 8
Re: TImage TmouseEvent stackframe issue
« Reply #2 on: August 03, 2021, 06:16:00 am »
This was an example distilled from a larger unit. I am working on an editor unit that handles many of it's own events and exhibits this issue. I was (lucky?) that this smaller code showed the same symptom.
« Last Edit: August 03, 2021, 06:29:10 am by 4nlegion »

4nlegion

  • New member
  • *
  • Posts: 8
Re: TImage TmouseEvent stackframe issue
« Reply #3 on: August 03, 2021, 06:40:01 am »
I just read a different Forum Post https://forum.lazarus.freepascal.org/index.php?topic=31306.0 and Thaddy replied with:
"...procedure of object has a hidden self pointer..."

Code: Pascal  [Select][+][-]
  1.   procedure DoSomeThing(Dummy:Pointer;Sender:TObject);
  2.   begin
  3.     writeln('Hello');
  4.   end;
  5.  
  6.  

so changing the previous event handler to:

Code: Pascal  [Select][+][-]
  1. procedure MouseDownEvent(Dummy:Pointer; Sender: TObject; Button: TMouseButton; Shift: TShiftState; X,Y: Integer);
  2. begin
  3.         if not (Sender is TImage) then exit;
  4.         Form1.ListBox1.Items.AddText(format('[x,y]: [%d,%d]',[x,y]));   // note NOW correct [x,y] reporting
  5. end;
  6.  
  7.  

...works as intended.

Many thanks!



« Last Edit: August 03, 2021, 06:48:31 am by 4nlegion »

4nlegion

  • New member
  • *
  • Posts: 8
Re: [SOLVED] TImage TmouseEvent stackframe issue
« Reply #4 on: August 03, 2021, 08:55:09 am »
In case anyone cares...

Combining lucamar's solution we have:

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5.         Classes, SysUtils, Forms, Controls, Graphics,Dialogs, StdCtrls, ExtCtrls;
  6. type
  7.         TImage1 = class(TImage)
  8.                 procedure DoOnMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X,Y: Integer);
  9.         end;
  10.  
  11.         TForm1 = class(TForm)
  12.                 ListBox1: TListBox;
  13.                 procedure FormCreate(Sender: TObject);
  14.         private
  15.         public
  16.         end;
  17.  
  18. var
  19.         Form1:  TForm1;
  20.         img:    TImage;
  21.  
  22. implementation
  23. {$R *.lfm}
  24. { TForm1 }
  25. procedure MouseDownEvent(Dummy:Pointer; Sender: TObject; Button: TMouseButton; Shift: TShiftState; X,Y: Integer);
  26. begin
  27.         if not (Sender is TImage) then exit;
  28.         Form1.ListBox1.Items.AddText(format('[x,y]: [%d,%d]',[x,y]));   // now is correct [x,y] reporting
  29. end;
  30.  
  31. procedure TImage1.DoOnMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X,Y: Integer);
  32. begin
  33.         if not (Sender is TImage) then exit;
  34.         Form1.ListBox1.Items.AddText(format('[x,y]: [%d,%d]',[x,y]));   // now is correct [x,y] reporting
  35. end;
  36.  
  37. procedure TForm1.FormCreate(Sender: TObject);
  38. var
  39.         e:      TMethod;
  40. begin
  41.         img:=TImage.create(Form1);
  42.         img.Parent:=Form1;
  43.         img.left:=32;
  44.         img.top:=32;
  45.         img.width:=400;
  46.         img.height:=400;
  47.         img.Canvas.Brush.Color := clgreen;
  48.         img.Canvas.Brush.style := bsSolid;
  49.         img.canvas.FillRect(0,0,400,400);
  50.  
  51.         e.Data:=img;
  52.         e.Code:=@TImage1.DoOnMouseDown; //MouseDownEvent;
  53.         img.OnMouseDown:=TMouseEvent(e);
  54. end;
  55.  
  56. end.

 

TinyPortal © 2005-2018