capture every mouse move in a TImage ( x,y )

I want to capture every mouse move inside a TImage, I mean every x,y position.


OnMouseMove is too slow and doesn't get at time all the moves..

bryan
LVL 3
bryan7Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

kambizCommented:
Windows does not generate WM_MOUSEMOVE for all mouse movements.

Kambiz
0
czykyCommented:
I concur with kambiz, depending on the speed the mouse is moved and other settings in the mouse control panel, you'll get different variations of MouseMove events and you can't count on every x,y that the mouse covers being forwarded to your program. (Also, if mouse gets scrolled off the image very quickly, you won't get the last movement or two, because they'll go to whatever control to which the mouse scrolled.)

Alternately, though, you can set a windows api hook to catch all the mouse events that are sent to your app (                KeyHook := SetWindowsHookEx(WH_MOUSE, @GetKeyHook, HInstance , 0);). With this filter, you'll be guaranteed all the mouse msgs sent to your app AND you can filter and/or modify them. I don't know that you'll find you're getting anymore information then you already are, although you'll have more control. And it's a lot more work for the hook.

One thought though: When you're inside a MouseMove event processing your mouse moves, you don't do an Application.ProcessMessages, do You? Or do you do processing that might cause another routine to process msgs in the background. If so, then you might lose mouse msgs.

Bottom line, MouseMove events is the way to go. That's what all the 'pro' apps do. Maybe if you briefly say what you are trying to accomplish with your mouse catching, others here can suggest some ideas.

Regards.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
SteveWaiteCommented:
You probably know this and need more positional info by the sound of it but h ere's a way that gets the current posion when you need it.

Set a timer off and ontimer find the current cursor position  using GetCursorPos(P)
Then compute relevant posion to your image using etc.
x := P.x - MyImage.ClientOrigin.x;
y := P.x - MyImage.ClientOrigin.y;

Maybe you need the memory of every posion the mouse has been to..
Hmm.. Thinking

Steve
0
CompTIA Cloud+

The CompTIA Cloud+ Basic training course will teach you about cloud concepts and models, data storage, networking, and network infrastructure.

bryan7Author Commented:
Adjusted points to 25
0
bryan7Author Commented:
I want to do a paint program.. i need to: catch every x,y of the mouse move INSIDE a TImage, draw a pixel there, and send the position over a socket to have a syncronized drawing board over tcp/ip

can I have an example on using the hook ? I never used hooks..
btw, I have RxLib which has a component that catches messages I think.. maybe I can use that ?

thanks
0
SteveWaiteCommented:
What about doing it a different way..
How about doing a regular paint  program using the timer method above. Then send just information about the changes to the other end?
0
bryan7Author Commented:
"just information about the changes to the other end? " 

yeah, but how do I paint ? when I move the mouse over the image i check if the left butt is pressed, but if I can't get every move I get only distant points in stead of lines..
0
SteveWaiteCommented:
OK..
Make a new app and drop a TImage on Form1.  Go to the Object inspector and double click the three events shown below. Then add the TRect variable to the forms private section (or public if you want to 'see' this var from other units). Now cut and past the contents of the event handlers from below. Have a good play with it.  Lot of things demo'd in there.
You would have to extend it with the timer technique shown earlier so the program can do updates as often as you need it within scope of performance.  
Then during each draw (on timer)you must send the coordinates when mouse goes down and while mouse is down is down then coord when mouse is up agian. Other computer then does the same draw code but from received coords.

Let me know how you get on. I can help more..

Note, a professional program would more likely use a TPaintBox and update it from it's onpaint event from a TBitmap which is acting as a back buffer. Then during the OnPaint the system will wait for the video trace to reach the bottom of the screen before painting the paintbox with the bitmap to avoid tearing on screen (flicker). This demo just paints straight onto the image and the image by definition holds a copy of the picture. A paintbox would not so has to be kept painted. The backbuffer would be painted via synchronize method in seperate thread. This makes stuff in the image keep moving smooth while user selects menus etc. Still, walk first, run later!

the demo..
//=========
unit RubberBandUnit;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics,
  Controls, Forms, Dialogs, ExtCtrls;

type
  TForm1 = class(TForm)
    Image1: TImage;
    procedure Image1MouseDown(Sender: TObject; Button:
      TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure Image1DragOver(Sender, Source: TObject;
      X, Y: Integer; State: TDragState; var Accept: Boolean);
    procedure Image1EndDrag(Sender, Target: TObject; X,Y: Integer);
  private
    { Private declarations }
    TheRect: TRect;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Image1MouseDown(Sender: TObject; Button:
  TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  TheRect := Bounds(X, Y, 0, 0);
  with Image1.Picture.Bitmap.Canvas do
  begin
    Brush.Style := bsClear;
    Pen.Color   := clWhite;
    Pen.Mode    := pmXor;
  end;
  Image1.BeginDrag(True);
end;

procedure TForm1.Image1DragOver(Sender, Source: TObject;
  X, Y: Integer; State: TDragState; var Accept: Boolean);
begin
  if (Source <> Sender)
    then Accept := False
    else
      with Image1.Picture.Bitmap.Canvas do
        with TheRect do
        begin
          Rectangle(Left, Top, Right, Bottom);
          BottomRight := Point(X,Y);
          Rectangle(Left, Top, Right, Bottom);
        end;
end;

procedure TForm1.Image1EndDrag(Sender, Target: TObject;
  X, Y: Integer);
begin
  if Target = Sender then // draw rectangle
  with Image1.Picture.Bitmap.Canvas do
  begin
    Pen.Color := clYellow;
    Pen.Mode  := pmCopy;
    Rectangle(TheRect.Left, TheRect.Top, X, Y);
  end
  else  // erasing
    with Image1.Picture.Bitmap.Canvas do
      with TheRect
        do Rectangle(Left, Top, Right, Bottom);
end;

end.
//=====

Steve
0
gandalf_the_whiteCommented:
listening...
0
bryan7Author Commented:
Adjusted points to 40
0
bryan7Author Commented:
SteveWaite.. thanks,, but .. maybe I missed something ? I tried the code but all I get is the mouse cursor changing.. I don't get any drawing..

what am I doing wrong ? must I do something more than that code ? I don't understand at all what you proposed about the timer,,
0
SteveWaiteCommented:
OK,

I left you with a little too much to find out.  Don't worry, nearly there.

You could load up an image using the object inspector by double clicking the 'Picture' property of Image1 and you would have seen some drawing!  Basically the image was uninitialised.

Here I’ve added the create event to the form and made the image fit the forms' client area and filled it with a color.

Now add this to the OnCreate event yourself..
//======
procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.Align := alClient;
  with Image1.Canvas do
  begin
    Pen.Color   := clBlack;
    Brush.Color := clBlack;
    FillRect(Rect(0, 0, Image1.Width, Image1.Height));
  end;
end;
//======

Now have a jolly good play with it.  Change colors and pen/brush styles etc. to see what the effects are.

Now this app simply draws everything as a result of normal screen updating, which will be too often for your proposed app.  So the timer method is would have to be employed in the end.

Now have a look at the graphex demo in ~\Delphi 3\Demos\DOC\GRAPHEX for loads more examples.  But that too just does all updates in form paint event.

To go further on..

Here is a line drawing app I knocked up quickly using a backbuffer, paintbox and timer.  (In your app you can send co-ordinate information to the other computer in ontimer event).

This is in straight line drawing mode You need to add different drawing modes to accommodate drawing dots, rectangles (like rubber band) and ellipses (use co-ordinates of rectangle but draw ellipse) etc.

Start a fresh app and drop a paintbox and timer on the form and flesh it out with the stuff below…

//=======
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    PaintBox1: TPaintBox;
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure PaintBox1Paint(Sender: TObject);
    procedure PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure PaintBox1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

const
  UpdateInterval = 100;

var
  Form1: TForm1;
  BackBuffer: TBitmap;
  x1, y1: Integer;  // stores position when  on mouse down
  x2, y2: Integer;  // stores position when mouse moving
  MouseIsDown: Boolean;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  MouseIsDown := False;
  x1 := 0;
  y1 := 0;
  x2 := 0;
  y2 := 0;

  PaintBox1.Left := 0;
  PaintBox1.Top := 0;
  PaintBox1.Width := ClientWidth;  // note use of ClientWidth, not Width
  PaintBox1.Height := ClientHeight;

  BackBuffer := TBitmap.Create;
  BackBuffer.Width := PaintBox1.ClientWidth;
  BackBuffer.Height := PaintBox1.ClientHeight;
  with BackBuffer.Canvas do
  begin
    Pen.Color := clBlack;
    Brush.Color := clBlack;
    FillRect(Rect(0, 0, BackBuffer.Width, BackBuffer.Height));
  end;

  Timer1.Interval := UpdateInterval;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  with PaintBox1.Canvas
    do Draw(0, 0, BackBuffer);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  BackBuffer.Free;
end;

procedure TForm1.PaintBox1Paint(Sender: TObject);
begin
  with PaintBox1.Canvas
    do Draw(0, 0, BackBuffer);
end;

procedure TForm1.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  MouseIsDown := True;
  x1 := X;
  y1 := Y;
  x2 := X;
  y2 := Y;
end;

procedure TForm1.PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  if MouseIsDown then
  begin
    with BackBuffer.Canvas do
    begin
      Brush.Style := bsClear;
      Pen.Color := clWhite;
      Pen.Mode := pmXor;
      MoveTo(x1, y1);
      LineTo(x2, y2);
      MoveTo(x1, y1);
      LineTo(X, Y);
    end;
    x2 := X;
    y2 := Y;
  end;
end;

procedure TForm1.PaintBox1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  MouseIsDown := False;
end;

end.
//=======

Now have another good mess about and let me know how you get on!

Steve.

0
SteveWaiteCommented:
How ya doin bryan!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.