bryan7
asked on
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
OnMouseMove is too slow and doesn't get at time all the moves..
bryan
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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
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
ASKER
Adjusted points to 25
ASKER
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
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
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?
How about doing a regular paint program using the timer method above. Then send just information about the changes to the other end?
ASKER
"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..
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..
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(Sen der: TObject; Button:
TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
TheRect := Bounds(X, Y, 0, 0);
with Image1.Picture.Bitmap.Canv as do
begin
Brush.Style := bsClear;
Pen.Color := clWhite;
Pen.Mode := pmXor;
end;
Image1.BeginDrag(True);
end;
procedure TForm1.Image1DragOver(Send er, Source: TObject;
X, Y: Integer; State: TDragState; var Accept: Boolean);
begin
if (Source <> Sender)
then Accept := False
else
with Image1.Picture.Bitmap.Canv as do
with TheRect do
begin
Rectangle(Left, Top, Right, Bottom);
BottomRight := Point(X,Y);
Rectangle(Left, Top, Right, Bottom);
end;
end;
procedure TForm1.Image1EndDrag(Sende r, Target: TObject;
X, Y: Integer);
begin
if Target = Sender then // draw rectangle
with Image1.Picture.Bitmap.Canv as do
begin
Pen.Color := clYellow;
Pen.Mode := pmCopy;
Rectangle(TheRect.Left, TheRect.Top, X, Y);
end
else // erasing
with Image1.Picture.Bitmap.Canv as do
with TheRect
do Rectangle(Left, Top, Right, Bottom);
end;
end.
//=====
Steve
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(Sen
TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
TheRect := Bounds(X, Y, 0, 0);
with Image1.Picture.Bitmap.Canv
begin
Brush.Style := bsClear;
Pen.Color := clWhite;
Pen.Mode := pmXor;
end;
Image1.BeginDrag(True);
end;
procedure TForm1.Image1DragOver(Send
X, Y: Integer; State: TDragState; var Accept: Boolean);
begin
if (Source <> Sender)
then Accept := False
else
with Image1.Picture.Bitmap.Canv
with TheRect do
begin
Rectangle(Left, Top, Right, Bottom);
BottomRight := Point(X,Y);
Rectangle(Left, Top, Right, Bottom);
end;
end;
procedure TForm1.Image1EndDrag(Sende
X, Y: Integer);
begin
if Target = Sender then // draw rectangle
with Image1.Picture.Bitmap.Canv
begin
Pen.Color := clYellow;
Pen.Mode := pmCopy;
Rectangle(TheRect.Left, TheRect.Top, X, Y);
end
else // erasing
with Image1.Picture.Bitmap.Canv
with TheRect
do Rectangle(Left, Top, Right, Bottom);
end;
end.
//=====
Steve
listening...
ASKER
Adjusted points to 40
ASKER
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,,
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,,
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(Send er: 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(Se nder: 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.
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:
Shift: TShiftState; X, Y: Integer);
procedure PaintBox1MouseMove(Sender:
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:
begin
with PaintBox1.Canvas
do Draw(0, 0, BackBuffer);
end;
procedure TForm1.FormDestroy(Sender:
begin
BackBuffer.Free;
end;
procedure TForm1.PaintBox1Paint(Send
begin
with PaintBox1.Canvas
do Draw(0, 0, BackBuffer);
end;
procedure TForm1.PaintBox1MouseDown(
Shift: TShiftState; X, Y: Integer);
begin
MouseIsDown := True;
x1 := X;
y1 := Y;
x2 := X;
y2 := Y;
end;
procedure TForm1.PaintBox1MouseMove(
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(Se
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.
How ya doin bryan!
Kambiz