4
votes

I like the idea of the Delphi Code Insight window (custom listbox on form without borders basically) where you can click outside of the form and it will close it automatically.

My first thought was to call SetCapture/ReleaseCapture in the FormCreate and FormDestroy respectively. I set the form's caption to X/Y on the FormMouseMove, but it doesn't update the coordinates outside of the form.

If I call SetCapture/ReleaseCapture from within MouseDown and MouseUp, it does update the coordinates as expected, so that proves the concept does work.

I tried other things as well, e.g. post a WM_USER in the OnShow event, and call SetCapture from there, but it still doesn't update the coordinates. I then tried the TApplicationEvents component (OnMessage), but that doesn't work either.

I've read several articles already, but wasn't able to find what I was looking for. Some articles called SetCapture from within the MouseMove, but that doesn't work when the mouse cursor starts outside of the form. Hrm...

The next step would be to use a WindowsHook, but that's where I stopped. I know how to implement one, but it just seems like I'm missing something really obvious here. There must be a simpler way to do this.

Any ideas? :)

Cheers, Jarno

3
Hi, sorry still pretty new here. ;) I actually discovered that this only partially solves the problem. When I click on another app, the WM_KILLFOCUS stops the modal form, but this doesn't work when I click on the main form of the same application. So I'm back to the above problem again.Jarno
Try to consider the mouse hooks as you mentioned. If you imagine, that you'll get all mouse messages wherever they happen. In the message handler is enough to filter "clicks" (mouse downs) and check if the cursor is over my form. If not, close the form. If yes, dispatch it. Sure you have to do something with your component(s) what can even invoke form close, because of infinite popup loop (as ShowModal do).user532231

3 Answers

1
votes

What you want can be done easier by adding TApplicationEvents to your form and use the event OnDeactivate. That one gets triggered whenever the application loses focus.

0
votes

Maybe WM_NCHITTEST can help you somehow. As they say, if the mouse is captured, this message is sent to the window that has captured the mouse. So I would capture the mouse for the form and then wait until result of this message is HTNOWHERE, which should mean "out of the window". But as far as I can remember, this never worked for me fine, so I finally used (as you mentioned) mouse hook.
But in my case I've had a lot of components on that popup form and you need to consider messaging for them too.
The implementation I've used (with a little changes) and which works is here.

0
votes

I had a similar problem (I needed to implement a scrolling windows if the mouse pointer hovered over a special area and I was not able to use SetCapture) and circumvented it using a timer + GetCursorPos method. Just do then a ScreenToClient and check if the mouse is within the window.