Link to home
Start Free TrialLog in
Avatar of dhowes_UK
dhowes_UKFlag for United Kingdom of Great Britain and Northern Ireland

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?



Avatar of atul_parmar
atul_parmar
Flag of India image

This might be because you are passing the MypaintBox.Parent.Handle
the handle of the parent.
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.
Avatar of dhowes_UK

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.
ASKER CERTIFIED SOLUTION
Avatar of Pierre Cornelius
Pierre Cornelius
Flag of South Africa image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Just curious, why a B-grade?
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
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
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
glad to help