Solved

How to use SetCapture without breaking TPaintbox event handling

Posted on 2006-06-20
10
1,316 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
 
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 500 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
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
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

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

708 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

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now