dhowes_UK
asked on
How to use SetCapture without breaking TPaintbox event handling
This is a tricky one, so points are awarded accordingly. Please note I need a solution to THIS problem not an alternative approach.
I have a TPaintBox aligned as alClient accross a standard windows form. I needed to track a users rubber band selection outside of the application window (which calls code to scroll the contents up, down etc).
I can't just use MouseMove to detect when the cursor has reached the end of the client area, because not all mousemove events are trapped by Delphi
So I call
SetCapture( MypaintBox.Parent.Handle );
in FormMouseDown in order to grab all MouseMove events
and then in FormMouseUp I call ReleaseCapture.
The problem is that after this, all MouseMove messages continue to come unmodifed from the parentform rather than adjusted to the Client area of the TPaintBox as before the call to SetCapture.
Is there any way to reset the previous behavior?
I have a TPaintBox aligned as alClient accross a standard windows form. I needed to track a users rubber band selection outside of the application window (which calls code to scroll the contents up, down etc).
I can't just use MouseMove to detect when the cursor has reached the end of the client area, because not all mousemove events are trapped by Delphi
So I call
SetCapture( MypaintBox.Parent.Handle );
in FormMouseDown in order to grab all MouseMove events
and then in FormMouseUp I call ReleaseCapture.
The problem is that after this, all MouseMove messages continue to come unmodifed from the parentform rather than adjusted to the Client area of the TPaintBox as before the call to SetCapture.
Is there any way to reset the previous behavior?
I didn't get what you said
....all MouseMove messages continue to come unmodifed from the parentform rather than adjusted to the Client area of the TPaintBox as before the call to SetCapture.
....all MouseMove messages continue to come unmodifed from the parentform rather than adjusted to the Client area of the TPaintBox as before the call to SetCapture.
ASKER
Usually the form hosting a TControl will recieve events on the controls behalf and then forward them based on the controls Coordinate system.
That's fine.
I doubt that the mouse is captured because as you said that you are calling setcapture on FormMouseDown and your paintbox is aligned to client so if mouse pointer is on paintbox, and if user clicks the mouse button it will not call the form's mousedown.
I doubt that the mouse is captured because as you said that you are calling setcapture on FormMouseDown and your paintbox is aligned to client so if mouse pointer is on paintbox, and if user clicks the mouse button it will not call the form's mousedown.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Just curious, why a B-grade?
ASKER
Hi, your response along with some of my own knowledge has allowed me to workaround the problem and is therefore good IMHO. My specific request was for a way to reset the event handling to the state it was in before SetCapture was used.
This would have been a perfect answer as it would solve the problem rather than work around it. As it stands, if I add any additional TPaintbox items to the same form in future modifications, I will also need to update the event redirection code. Not too much of a problem for myself but when the code is changed by others it won't be obvious where any problems are coming from.
So I figured it was a B but a high B
This would have been a perfect answer as it would solve the problem rather than work around it. As it stands, if I add any additional TPaintbox items to the same form in future modifications, I will also need to update the event redirection code. Not too much of a problem for myself but when the code is changed by others it won't be obvious where any problems are coming from.
So I figured it was a B but a high B
I'm not arguing about the grade, but whenever I get a B grade without further questions or feedback from the asker when I think the solution was given makes me wonder why the asker wasn't happy. I like to know what did not work for them or why. The objective is to help the asker not to gain as many experts points as possible (that's just an added bonus along with the fact that I learn a lot from others here). That's why its always a good idea to give the expert a chance to elaborate or provide a better solution before accepting an answer if you were not 100% satisfied. Based on your last comment, I'm giving you a different proposed solution.
My initial solution was given based on the assumption that you wanted to keep the approach of having the form manage mouse events, however, I believe it would be better to let the Paintbox do so. The only remaining thing to do then is to forward any mousedown messages from the form to the paintbox for mouse clicks outside of the paintbox. With this in mind, I would rather have done something as follows:
PAS File:
========================== ========== ========== ========== ======
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls;
type
TForm1 = class(TForm)
Panel1: TPanel;
PaintBox1: TPaintBox;
procedure PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer);
procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
procedure PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure PaintBox1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.PaintBox1MouseDown( Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
SetCaptureControl(PaintBox 1);
end;
procedure TForm1.PaintBox1MouseUp(Se nder: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
ReleaseCapture;
end;
procedure TForm1.PaintBox1MouseMove( Sender: TObject; Shift: TShiftState; X,Y: Integer);
var c: TControl;
s: string;
begin
c:= GetCaptureControl;
if c = nil
then s:= 'None'
else s:= c.Name;
Caption:= Format('CaptureControl: %s, x: %d y: %d', [s, x,y]);
end;
procedure TForm1.FormMouseDown(Sende r: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
PaintBox1.Perform(WM_LButt onDown, 0, x + (y SHL 16));
end;
procedure TForm1.FormMouseMove(Sende r: TObject; Shift: TShiftState; X, Y: Integer);
var c: TControl;
s: string;
begin
c:= GetCaptureControl;
if c = nil
then s:= 'None'
else s:= c.Name;
Caption:= Format('CaptureControl: %s, x: %d y: %d', [s, x,y]);
end;
end.
DFM File:
========================== ========== ========== ========== ====
object Form1: TForm1
Left = 192
Top = 114
Width = 696
Height = 480
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
OnMouseDown = FormMouseDown
OnMouseMove = FormMouseMove
PixelsPerInch = 96
TextHeight = 13
object Panel1: TPanel
Left = 192
Top = 112
Width = 281
Height = 161
Caption = 'Panel1'
TabOrder = 0
object PaintBox1: TPaintBox
Left = 1
Top = 1
Width = 279
Height = 159
Align = alClient
OnMouseDown = PaintBox1MouseDown
OnMouseMove = PaintBox1MouseMove
OnMouseUp = PaintBox1MouseUp
end
end
end
Kind Regards
Pierre
My initial solution was given based on the assumption that you wanted to keep the approach of having the form manage mouse events, however, I believe it would be better to let the Paintbox do so. The only remaining thing to do then is to forward any mousedown messages from the form to the paintbox for mouse clicks outside of the paintbox. With this in mind, I would rather have done something as follows:
PAS File:
==========================
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls;
type
TForm1 = class(TForm)
Panel1: TPanel;
PaintBox1: TPaintBox;
procedure PaintBox1MouseMove(Sender:
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer);
procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
procedure PaintBox1MouseDown(Sender:
Shift: TShiftState; X, Y: Integer);
procedure PaintBox1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.PaintBox1MouseDown(
Shift: TShiftState; X, Y: Integer);
begin
SetCaptureControl(PaintBox
end;
procedure TForm1.PaintBox1MouseUp(Se
Shift: TShiftState; X, Y: Integer);
begin
ReleaseCapture;
end;
procedure TForm1.PaintBox1MouseMove(
var c: TControl;
s: string;
begin
c:= GetCaptureControl;
if c = nil
then s:= 'None'
else s:= c.Name;
Caption:= Format('CaptureControl: %s, x: %d y: %d', [s, x,y]);
end;
procedure TForm1.FormMouseDown(Sende
Shift: TShiftState; X, Y: Integer);
begin
PaintBox1.Perform(WM_LButt
end;
procedure TForm1.FormMouseMove(Sende
var c: TControl;
s: string;
begin
c:= GetCaptureControl;
if c = nil
then s:= 'None'
else s:= c.Name;
Caption:= Format('CaptureControl: %s, x: %d y: %d', [s, x,y]);
end;
end.
DFM File:
==========================
object Form1: TForm1
Left = 192
Top = 114
Width = 696
Height = 480
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
OnMouseDown = FormMouseDown
OnMouseMove = FormMouseMove
PixelsPerInch = 96
TextHeight = 13
object Panel1: TPanel
Left = 192
Top = 112
Width = 281
Height = 161
Caption = 'Panel1'
TabOrder = 0
object PaintBox1: TPaintBox
Left = 1
Top = 1
Width = 279
Height = 159
Align = alClient
OnMouseDown = PaintBox1MouseDown
OnMouseMove = PaintBox1MouseMove
OnMouseUp = PaintBox1MouseUp
end
end
end
Kind Regards
Pierre
ASKER
Thanks, your latest post is pretty close, to my eventual solution, though yours is a bit tighter and I've modified my code accordingly. I also take your point about giving time to respond before posting a grade.
Much appreciated
David
Much appreciated
David
glad to help
the handle of the parent.