Board index » delphi » Detecting mousedown outside modal window

Detecting mousedown outside modal window

Hello

I wish to detect mousedown outside a modal window, and if mouse
has been pressed outside, I want to close the modal window.

Thanks,
--
Jacob Pedersen
AK Techotel
J.Peder...@nospamtechotel.dk
(Remove nospam when replying!)

 

Re:Detecting mousedown outside modal window


To detect a MouseDown outside the bounds of your app, you'll need a Mouse
Hook.  See SetWindowsHookEx

Cheers,
Rik.

Quote
Jacob Pedersen <J.Peder...@techotel.dk> wrote in message

news:Xns90E25DEFFCE39jpedersentechotel@207.105.83.65...
Quote
> Hello

> I wish to detect mousedown outside a modal window, and if mouse
> has been pressed outside, I want to close the modal window.

> Thanks,
> --
> Jacob Pedersen
> AK Techotel
> J.Peder...@nospamtechotel.dk
> (Remove nospam when replying!)

Re:Detecting mousedown outside modal window


In article <Xns90E25DEFFCE39jpedersentecho...@207.105.83.65>, Jacob
Quote
Pedersen wrote:
> I wish to detect mousedown outside a modal window, and if mouse
> has been pressed outside, I want to close the modal window.

In fact this is not quite as easy as it sounds.

Usually one solves this problem by grabbing the mouse capture, so even
mouse events outside the form are "seen" by the form. But there are
many controls that will grab the capture when the user clicks on them,
so one cannot rely on this method unless the form does not contain
controls that grab capture when clicked on. Which basically leaves us
with a not quite perfect kludge: a timer that checks moouse position
and button state in short intervals and closes the form if it sees a
mouse down outside the form.

The timer in the example has an interval of 100 msecs and is enabled at
design-time:

procedure TForm2.Timer1Timer(Sender: TObject);
begin
  If Showing and (GetAsyncKeyState( VK_LBUTTON ) < 0) Then
    If not PtInRect( BoundsRect, Mouse.CursorPos )
    Then
      Close;
end;

It is not totally perfect, a very fast click can escape its notice. One
could reduce the interval to minimize that but at the cost of
increasing CPU load a bit. The alternative, as posted by Rik, is to use
a thread-specific windows hook, type WH_MOUSE.

Peter Below (TeamB)  100113.1...@compuserve.com)
No e-mail responses, please, unless explicitly requested!
Note: I'm unable to visit the newsgroups every day at the moment,
so be patient if you don't get a reply immediately.

Re:Detecting mousedown outside modal window


"Peter Below (TeamB)" <100113.1...@compuXXserve.com> wrote in
news:VA.000074db.0097bf4d@antispam.compuserve.com:

Quote
> procedure TForm2.Timer1Timer(Sender: TObject);
> begin
>   If Showing and (GetAsyncKeyState( VK_LBUTTON ) < 0) Then
>     If not PtInRect( BoundsRect, Mouse.CursorPos )
>     Then
>       Close;
> end;

> It is not totally perfect, a very fast click can escape its notice. One
> could reduce the interval to minimize that but at the cost of
> increasing CPU load a bit. The alternative, as posted by Rik, is to use
> a thread-specific windows hook, type WH_MOUSE.

Thanks Peter.

using your code at 50 msec yeilded a cpu load of 1% on a 800 mhz Pentium3
which is not a terrible fast computer.

Is there somehow I can pass on the mouse click to the underlying form? So
that the control I pressed outside my modal window clicked.

Thanks,
--
Jacob Pedersen
AK Techotel
J.Peder...@nospamtechotel.dk
(Remove nospam when replying!)

Re:Detecting mousedown outside modal window


Quote
"Jacob Pedersen" <J.Peder...@techotel.dk> wrote in message

news:Xns90E25DEFFCE39jpedersentechotel@207.105.83.65...

Quote
> I wish to detect mousedown outside a modal window, and if mouse
> has been pressed outside, I want to close the modal window.

Don't make it modal, and hide the form on the Deactivate event.

--
Antony Hoon
Delphi {*word*60}ed
(Replace 4x7 with 7777 to reply..)

Re:Detecting mousedown outside modal window


"Antony Hoon" <antony...@telkom.net> wrote in news:3b559f96_1@dnews:

Quote

Actually I have to return some stuff to the caller. Then I need to assign
events and stuff.
Modalway is easier.

Thanks,
--
Jacob Pedersen
AK Techotel
J.Peder...@nospamtechotel.dk
(Remove nospam when replying!)

Re:Detecting mousedown outside modal window


In article <Xns90E29C1D2741Ejpedersentecho...@207.105.83.65>, Jacob

Quote
Pedersen wrote:
> Is there somehow I can pass on the mouse click to the underlying form?

That should happen automatically. The way focus capture works in Win32
is that you get the mouse down (but not mous move) message but the
window beneath the mouse also gets it.

Oh, i probably see your problem. You are clicking on the disabled form
beneath the modal form and since it  is disabled it does not get the
mouse message. Try to fake another mouse click at the current position
with

  mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 );
  mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 );

If you are lucky it will get processed after the modal form has closed
and the form underneath has reverted to enabled state.

Peter Below (TeamB)  100113.1...@compuserve.com)
No e-mail responses, please, unless explicitly requested!
Note: I'm unable to visit the newsgroups every day at the moment,
so be patient if you don't get a reply immediately.

Re:Detecting mousedown outside modal window


Hi,

Quote
> Actually I have to return some stuff to the caller. Then I need to
assign
> events and stuff.
>Is there somehow I can pass on the mouse click to the underlying
form? So
>that the control I pressed outside my modal window clicked.

Below is a dirty way so you can do all the above..

You can trap the Applicaiton.OnDeactivate and the form's deactivate..
Try it like this:

In the calling form:
var theForm: TForm;     // Global Variable

function MyShowModal(f: TForm): TModalResult;
var m: THandle;
    OldAppDeac: TNotifyEvent;
begin
  f.Show;
  theForm := f;
  OldAppDeac := Application.OnDeactivate;
  Application.OnDeactivate := Form1.MyAppDeactivate;
  while f.Visible do Application.ProcessMessages;
  Application.OnDeactivate := OldAppDeac;
  if (LongInt(theForm) = 0) and assigned(Application.OnDeactivate)
then
    Application.OnDeactivate(Application);
  Result := f.Modalresult;
end;

procedure TForm1.MyAppDeactivate(Sender: TObject);
begin
  theForm.Close;
  LongInt(theForm) := 0;
end;

Called with:

  Form2.ModalResult := mrOK; // Default result if click outside of
form
  // Setup
  if MyShowModal(Form2) = mrOK then
    label1.caption := 'ok'
  else
    label1.caption := 'no';

In the called form:
Juat make sure after you set the ModalResult value in the *modal*
form, you issue a close, including TBitBtn.

Quote
> Modalway is easier.

Agree on that.. until your requirements shows up.. <g>

--
Antony Hoon
Delphi {*word*60}ed
(Replace 4x7 with 7777 to reply..)

Re:Detecting mousedown outside modal window


Quote
Jacob Pedersen wrote in message ...

>Thanks Peter.

>using your code at 50 msec yeilded a cpu load of 1% on a 800 mhz Pentium3
>which is not a terrible fast computer.

>Is there somehow I can pass on the mouse click to the underlying form? So
>that the control I pressed outside my modal window clicked.

Yes, re-read Peter's and Rik's messages again.

Quote
>> increasing CPU load a bit. The alternative, as posted by Rik, is to use
>> a thread-specific windows hook, type WH_MOUSE.

^^^^^^^^^^^^^^^^^^^^^^^^^

--
Robert

Re:Detecting mousedown outside modal window


"Peter Below (TeamB)" <100113.1...@compuXXserve.com> wrote in
news:VA.000074eb.00419515@antispam.compuserve.com:

Quote
> If you are lucky it will get processed after the modal form has closed
> and the form underneath has reverted to enabled state.

> Peter Below (TeamB)  100113.1...@compuserve.com)
> No e-mail responses, please, unless explicitly requested!
> Note: I'm unable to visit the newsgroups every day at the moment,
> so be patient if you don't get a reply immediately.

Peter, you are too cool. It works very well so far :)

--
Jacob Pedersen
AK Techotel
J.Peder...@nospamtechotel.dk
(Remove nospam when replying!)

Re:Detecting mousedown outside modal window


"Antony Hoon" <antony...@telkom.net> wrote in news:3b56444c_2@dnews:

Quote
> Hi,

>> Actually I have to return some stuff to the caller. Then I need to
>> assign events and stuff.
>>Is there somehow I can pass on the mouse click to the underlying form?
>>So that the control I pressed outside my modal window clicked.
> Below is a dirty way so you can do all the above..

> You can trap the Applicaiton.OnDeactivate and the form's deactivate..
> Try it like this:

> In the calling form:
> var theForm: TForm;     // Global Variable

> function MyShowModal(f: TForm): TModalResult;
> var m: THandle;
>     OldAppDeac: TNotifyEvent;
> begin
>   f.Show;
>   theForm := f;
>   OldAppDeac := Application.OnDeactivate;
>   Application.OnDeactivate := Form1.MyAppDeactivate;
>   while f.Visible do Application.ProcessMessages;
>   Application.OnDeactivate := OldAppDeac;
>   if (LongInt(theForm) = 0) and assigned(Application.OnDeactivate)
> then
>     Application.OnDeactivate(Application);
>   Result := f.Modalresult;
> end;

> procedure TForm1.MyAppDeactivate(Sender: TObject);
> begin
>   theForm.Close;
>   LongInt(theForm) := 0;
> end;

> Called with:

>   Form2.ModalResult := mrOK; // Default result if click outside of
> form
>   // Setup
>   if MyShowModal(Form2) = mrOK then
>     label1.caption := 'ok'
>   else
>     label1.caption := 'no';

> In the called form:
> Juat make sure after you set the ModalResult value in the *modal*
> form, you issue a close, including TBitBtn.

>> Modalway is easier.
> Agree on that.. until your requirements shows up.. <g>

> --
> Antony Hoon
> Delphi {*word*60}ed
> (Replace 4x7 with 7777 to reply..)

Phew, this looks advanced :)

A simple timer on the modal form with the following code, does the trick. I
have originally set the timer to 1000, this is to get rid of a doubleclick
problem.

procedure TfrmPlusProduct.TimerTimer(Sender: TObject);
const
  TimerInterval = 50;
begin
  if Timer.Interval > TimerInterval then
  begin
    Timer.Enabled := False;
    Timer.Interval := TimerInterval;
    Timer.Enabled := True;
  end;
  if Showing and (GetAsyncKeyState(VK_LBUTTON) < 0) Then
    if not PtInRect(BoundsRect, Mouse.CursorPos) then
    begin
      Close;
      ModalResult := bbOk.ModalResult;
      mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 );
      mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 );
    end;
end;

Thanks for your time,
--
Jacob Pedersen
AK Techotel
J.Peder...@nospamtechotel.dk
(Remove nospam when replying!)

Re:Detecting mousedown outside modal window


Jacob Pedersen <J.Peder...@techotel.dk> wrote in
news:Xns90E37865AB734jpedersentechotel@207.105.83.65:

Quote
> "Peter Below (TeamB)" <100113.1...@compuXXserve.com> wrote in
> news:VA.000074eb.00419515@antispam.compuserve.com:

>> If you are lucky it will get processed after the modal form has closed
>> and the form underneath has reverted to enabled state.

>> Peter Below (TeamB)  100113.1...@compuserve.com)
>> No e-mail responses, please, unless explicitly requested!
>> Note: I'm unable to visit the newsgroups every day at the moment, so be
>> patient if you don't get a reply immediately.

> Peter, you are too cool. It works very well so far :)

Except if I hold down the button and move the mouse outside the form's
area. This is detected as being pressed outside which it's not.
Can this be fixed so that it only reacts if the mouse it released outside
the form.

Thanks for any help!
--
Jacob Pedersen
AK Techotel
J.Peder...@nospamtechotel.dk
(Remove nospam when replying!)

Re:Detecting mousedown outside modal window


In article <Xns90E38AD2DDFD9jpedersentecho...@207.105.83.65>, Jacob Pedersen
wrote:

Quote
> Except if I hold down the button and move the mouse outside the form's
> area. This is detected as being pressed outside which it's not.
> Can this be fixed so that it only reacts if the mouse it released outside
> the form.

With a bit more work. You have to change the timer proc to keep track of the
result of its check the last time it was called. If the test shows mouse
down outside the form and the *last* one showed mouse up but outside the
form you can presume you have a click.

Peter Below (TeamB)  100113.1...@compuserve.com)
No e-mail responses, please, unless explicitly requested!
Note: I'm unable to visit the newsgroups every day at the moment,
so be patient if you don't get a reply immediately.

Re:Detecting mousedown outside modal window


"Peter Below (TeamB)" <100113.1...@compuXXserve.com> wrote in
news:VA.000074f6.006da32e@antispam.compuserve.com:

Quote
> In article <Xns90E38AD2DDFD9jpedersentecho...@207.105.83.65>, Jacob
> Pedersen wrote:
>> Except if I hold down the button and move the mouse outside the form's
>> area. This is detected as being pressed outside which it's not.
>> Can this be fixed so that it only reacts if the mouse it released
>> outside the form.

> With a bit more work. You have to change the timer proc to keep track
> of the result of its check the last time it was called. If the test
> shows mouse down outside the form and the *last* one showed mouse up
> but outside the form you can presume you have a click.

That was what I was thinking but hoping of a better way.

Btw I noticed that all this only works within my app. For example pressing
a button in the quicklaunch area, don't work. Not possible or easy fix?

Thanks!
--
Jacob Pedersen
AK Techotel
J.Peder...@nospamtechotel.dk
(Remove nospam when replying!)

Re:Detecting mousedown outside modal window


In article <Xns90E460022CB9Bjpedersentecho...@207.105.83.65>, Jacob Pedersen
wrote:

Quote
> Btw I noticed that all this only works within my app. For example pressing
> a button in the quicklaunch area, don't work. Not possible or easy fix?

I don't see why it would not work, sorry. A mouse down is a mouse down <g>.

Peter Below (TeamB)  100113.1...@compuserve.com)
No e-mail responses, please, unless explicitly requested!
Note: I'm unable to visit the newsgroups every day at the moment,
so be patient if you don't get a reply immediately.

Go to page: [1] [2]

Other Threads