Solved

How to use SetCapture without breaking TPaintbox event handling

Posted on 2006-06-20
10
1,413 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
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
 
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

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

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

Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Do you want to know how to make a graph with Microsoft Access? First, create a query with the data for the chart. Then make a blank form and add a chart control. This video also shows how to change what data is displayed on the graph as well as form…
In this video you will find out how to export Office 365 mailboxes using the built in eDiscovery tool. Bear in mind that although this method might be useful in some cases, using PST files as Office 365 backup is troublesome in a long run (more on t…
Suggested Courses
Course of the Month10 days, 5 hours left to enroll

623 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