0

Ok I have a function that returns to me a TMouseEvent type

I need to execute returned TMouseEvent but I dont know how.

Simple function returning an event:

function OMDold(obj: TObject): TMouseEvent
  begin
  ... //some operations on obj 
  result := obj.OnMouseDown; //there is casting necessary, I skip it for simplify
end; 

Currently the event is set to OMDnew which looks like:

procedure TfmAPRBasedForm.TSDragEvent(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if something then dosomething
  else
    begin
      Sender.OnMouseDOwn := OMDold // OMDold in most cases returns null but its ok I just want to clear custom event from the object 
      //line below is a point of my question - the one I used doesnt work
      TButton(Sender).OnMouseDown(Sender,Button,Shift,X,Y) //this line throws Access viloation at me
    end;
end;

What I'm trying to achieve:

  1. Geting button default OnMouseDown event and storing it in some record data

  2. Changing ONMouseDown event to custom

  3. During the custom event procedure there is a condition - if the mouse press was a drag, I execute drag code, if it wasn't I'd proceed with common click

  4. To procced with common click I wanted to restore the default event and reeru it so the click could be executed

Thats it

Andrea
  • 11,801
  • 17
  • 65
  • 72
Jacek Kwiecień
  • 12,397
  • 20
  • 85
  • 157
  • Why don't you just call `OMDnew`. You can do that you know. – David Heffernan Mar 15 '12 at 09:11
  • what is the problem to directly call `OMDnew(sender, button, shift, x,y)` ? – teran Mar 15 '12 at 09:14
  • My description wasn't clear enough. Justmade probably just gave me the right answer. I edited my post however, for further use :) – Jacek Kwiecień Mar 15 '12 at 09:26
  • Rethought, still not clear to me. Editet my post – Jacek Kwiecień Mar 15 '12 at 09:34
  • If your OMDold is stored as TMethod then you can use : TMouseEvent(OMDOld)(Sender,Button,Shift,X,Y); – Justmade Mar 15 '12 at 09:58
  • 1
    As you said, Sender.OnMouseDOwn := OMDold usually return nil (not null). That mean Sender.OnMouseDOwn is also nil. That's why you get AV from invoking it. You need to add If Assigned(Sender.OnMouseDOwn) then before calling TButton(Sender).OnMouseDown so that it is skipped when Sender.OnMouseDown is empty. – Justmade Mar 15 '12 at 14:07
  • Yah, the point I don't really wanna skip it. I want to proceed with a click which is ruined because of that custom event. I'm starting to think that I'll have to do TButton(Sender).OnClick(Sender); if assigned returns false – Jacek Kwiecień Mar 15 '12 at 14:29
  • 1
    I had already answered your original question, though it might not actually solved your problem as you had not bring out your problem clearly. Keep changing the question is not a good way of getting more help. If you new question is indeed quite different from the original one, you are better asking a new question. – Justmade Mar 16 '12 at 07:16

3 Answers3

3

Just call it directly passing the param :

procedure TfmAPRBasedForm.TSDragEvent(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if something then dosomething
  else
    begin
      TButton(Sender.OnMouseDOwn) := OMDold // OMDold in most cases returns nil (not null) but its ok I just want to clear custom event from the object 
      //line below is a point of my question - the one I used doesnt work
      If Assigned(TButton(Sender).OnMouseDown) then // Check if there is really an TMouseEvent
        TButton(Sender).OnMouseDown(Sender,Button,Shift,X,Y) //Call only when Event exist
    end;
end;

You may need to changed the Button, Shift, X, Y though if you are using them in your OMDOld and you need the value other then current value in the dragEvent, like removing ssShift or so.

If your OMDold is stored as TMethod then you can use :

TMouseEvent(OMDOld)(Sender,Button,Shift,X,Y);

Below is a full test example adjusted to show what you want to achieve in similar fashion :

Unit Unit4;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm4 = class(TForm)
    btn1: TButton;
    btn2: TButton;
    procedure FormCreate(Sender: TObject);
    procedure btn1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure btn2MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  private
    { Private declarations }
    procedure NewMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  public
    { Public declarations }
    OMDold : TMouseEvent;
    IsNew : Boolean;
  end;

var
  Form4: TForm4;

implementation

{$R *.dfm}

procedure TForm4.FormCreate(Sender: TObject);
begin
  OMDold := btn1.OnMouseDown;
  btn1.OnMouseDown := NewMouseDown;
  IsNew := True;
end;

procedure TForm4.NewMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if IsNew then
    ShowMessage('New Method!')
  else if Assigned(OMDold) then
    OMDold(Sender,Button,Shift,X,Y);
end;

procedure TForm4.btn1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  ShowMessage('Original Method!');
end;

procedure TForm4.btn2MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  IsNew := not IsNew;
end;

end.
Justmade
  • 1,496
  • 11
  • 16
  • Edited my post, I'm not sure if its what I'm looking for – Jacek Kwiecień Mar 15 '12 at 09:35
  • @JacekKwiecień It is all the same, just call OMDOld(Sender,Button,Shift,X,Y); – Justmade Mar 15 '12 at 09:43
  • OMDOld can be Nil, so additional check is required. – Torbins Mar 15 '12 at 10:30
  • it throws access violation at me :( I'm sure OMDold returns proper event - I use OMDold(Sender)(Sender,Button,Shift,X,Y); – Jacek Kwiecień Mar 15 '12 at 10:51
  • tried (Sender).OnMouseDown(Sender,Button,Shift,X,Y); but throws exception too – Jacek Kwiecień Mar 15 '12 at 11:33
  • @Jacek AV mean that the OMDold (or Sender.OnMouseDown is nil as Torbins suggested. My former version do include a Assigned check. – Justmade Mar 15 '12 at 11:50
  • added Assigned condition, why does that return false if I did Sender.OnMouseDOwn := OMDold – Jacek Kwiecień Mar 15 '12 at 12:14
  • 1
    @Jacek, that mean your OMDold hold nothing. For example, you assigned the OMDold by OMDold := button1.OnMouseDown. However, button1 do not have an OnMouseDown event at that moment, then you assign nothing to OMDold and it will of cause return false to Assign and cause AV when used. – Justmade Mar 15 '12 at 12:19
  • Thats right, the previous OnMouseDown was empty. However I can set it to empty. It works fine but during the next click. When I call it from inside the event it throws the exception – Jacek Kwiecień Mar 15 '12 at 13:42
  • @JacekKwiecień I think you need to provide real (maybe simplified) code for us to understand. You can use my sample code to modify to show your problem. Also, if you call the event inside the same event without exit control, you will definitely got an exception same with this forum name! – Justmade Mar 15 '12 at 13:50
  • modified code a little bit + added desciption of what i'm trying to achieve. The code I'm presenting is simplified only a little bit. It basically presents everything I want to do – Jacek Kwiecień Mar 15 '12 at 14:07
0

The sample procedure that stops OnMouseDown from runing the CLick event:

procedure TForm1.CustomowyEvent(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
if (DragDetectPlus(TWinControl(Sender))) then ShowMessage('detected drag!')

else
  begin
    TButton(Sender).OnMouseDown := DME;
    TButton(Sender).OnClick(Sender);
  end;
end;

TButton(Sender).OnClick(Sender) runs the click so basically if we didn't want to drag it clicks.

Jacek Kwiecień
  • 12,397
  • 20
  • 85
  • 157
  • 1
    Well this is quite another issue then your question "Using TMouseEvent type to call an event from code" :) – Justmade Mar 15 '12 at 14:41
  • 1
    Just one off topic note if I see the `DragDetectPlus`. I hope this function do more than check if the control is being dragged, because if not it would be better to use the `Dragging` function. – TLama Mar 15 '12 at 15:23
  • 1
    The one, which has each `TControl` descendant. If the [`Dragging`](http://docwiki.embarcadero.com/Libraries/en/Vcl.Controls.TControl.Dragging) returns True, the control is being dragged. It was a sidenote to your `DragDetectPlus` function name, so I was wondering what it actually does ;-) – TLama Mar 16 '12 at 12:50
0

Addressing all question parts separately:

  1. Geting button default OnMouseDown event and storing it in some record data

    Add a private field to your form declaration and assign the old event to it:

      private
        FOldButtonOnMouseDown: TMouseEvent;
      end;
    
    ...
    
      FOldButtonOnMouseDown := Button.OnMouseDown;
    
  2. Changing OnMouseDown event to custom

    Assign your custom event handler to the OnMouseDown property:

      private
        procedure NewButtonMouseDown(Sender: TObject; Button: TMouseButton;
          Shift: TShiftState; X, Y: Integer);
      end;
    
    ...
    
      Button.OnMouseDown := NewButtonMouseDown;
    
  3. During the custom event procedure there is a condition - if the mouse press was a drag, I execute drag code, if it wasn't I'd proceed with common click

    Test if the original event was assigned and if so, call it:

    procedure TForm1.NewButtonMouseDown(Sender: TObject; 
      Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    begin
      if DragCondition then
        ExecuteDragCode
      else
        if Assigned(FOldButtonOnMouseDown) then
          FOldButtonOnMouseDown(Sender, Button, Shift, X, Y);
    end;
    
  4. To procced with common click I wanted to restore the default event and rerun it so the click could be executed

    Restore the event:

    Button.OnMouseDown := FOldButtonOnMouseDown;
    

Combining this all together is your next challenge. It depends especially on how the drag stuf is implemented, but you could take a look at this answer in which I also temporarily exchange the OnMouseUp event for undoing all changes.

Community
  • 1
  • 1
NGLN
  • 43,011
  • 8
  • 105
  • 200