Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

How to use SetCapture without breaking TPaintbox event handling

Posted on 2006-06-20
10
Medium Priority
?
1,461 Views
Last Modified: 2012-06-27
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?



0
Comment
Question by:dhowes_UK
  • 4
  • 3
  • 3
10 Comments
 
LVL 10

Expert Comment

by:atul_parmar
ID: 16940772
This might be because you are passing the MypaintBox.Parent.Handle
the handle of the parent.
0
 
LVL 10

Expert Comment

by:atul_parmar
ID: 16940801
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.
0
 

Author Comment

by:dhowes_UK
ID: 16940829
Usually the form hosting a TControl will recieve events on the controls behalf and then forward them based on the controls Coordinate system.
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
LVL 10

Expert Comment

by:atul_parmar
ID: 16941012
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.
0
 
LVL 14

Accepted Solution

by:
Pierre Cornelius earned 1500 total points
ID: 16943346
Use the ParentToClient function and forward the message. Something like this:

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 FormMouseUp(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  Caption:= Format('x: %d  y: %d', [x,y]);
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  SetCapture(TWincontrol(PaintBox1).Handle);
end;

procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  ReleaseCapture;
end;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var p: TPoint;
begin
  if (GetCapture = PaintBox1.Parent.Handle) then
  begin
    p:=PaintBox1.ParentToClient(point(x,y), PaintBox1.Parent);
    PaintBox1MouseMove(Sender, Shift, p.X,p.y);
  end;
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
  OnMouseUp = FormMouseUp
  PixelsPerInch = 96
  TextHeight = 13
  object Panel1: TPanel
    Left = 48
    Top = 48
    Width = 281
    Height = 161
    Caption = 'Panel1'
    TabOrder = 0
    object PaintBox1: TPaintBox
      Left = 1
      Top = 1
      Width = 279
      Height = 159
      Align = alClient
      OnMouseMove = PaintBox1MouseMove
    end
  end
end

Regards
Pierre
0
 
LVL 14

Expert Comment

by:Pierre Cornelius
ID: 16966605
Just curious, why a B-grade?
0
 

Author Comment

by:dhowes_UK
ID: 16967087
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
0
 
LVL 14

Expert Comment

by:Pierre Cornelius
ID: 16969487
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(PaintBox1);
end;

procedure TForm1.PaintBox1MouseUp(Sender: 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(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  PaintBox1.Perform(WM_LButtonDown, 0, x + (y SHL 16));
end;

procedure TForm1.FormMouseMove(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;

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
0
 

Author Comment

by:dhowes_UK
ID: 16970158
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
0
 
LVL 14

Expert Comment

by:Pierre Cornelius
ID: 16981570
glad to help
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
We’ve all felt that sense of false security before—locking down external access to a database or component and feeling like we’ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many w…
Are you ready to place your question in front of subject-matter experts for more timely responses? With the release of Priority Question, Premium Members, Team Accounts and Qualified Experts can now identify the emergent level of their issue, signal…

885 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question