How to detect a mouse click outside of a Popup form (1 Viewer)

tvanstiphout

Active member
Local time
Yesterday, 22:38
Joined
Jan 22, 2016
Messages
222
I'm writing a tool window, a filter form for Continuous Forms, similar to what MSFT implemented for Datasheet (the downward pointing triangle).

If you use that feature in Datasheet, and you click outside of it, it disappears.

Of course MSFT's version is not an Access form, but something fancy that is not easily reproducible. So I am using an Access form with Popup=Yes. Of course Modal=No.

When we click outside a Popup form, it does not raise any events in the popup, not Form_LostFocus, not Form_Deactivate.
I’m thinking I will have to resort to form subclassing (which I am willing to do) but I’m not sure what APIs could be used to detect we are clicking outside the popup. Maybe inspect all mouse clicks for x,y outside of the popup’s area? Maybe the NCHITTEST event?

SysTextFilter.png
 

arnelgp

..forever waiting... waiting for jellybean!
Local time
Today, 13:38
Joined
May 7, 2009
Messages
19,243
maybe add code to the Click Event (Form click, Detail Click, Header/Footer Click) of the "outside" form, detecting first if the Pop-up is Loaded.
If it is then close it.
 

tvanstiphout

Active member
Local time
Yesterday, 22:38
Joined
Jan 22, 2016
Messages
222
That won't work. The click may be on the Desktop, or any other app.
 

tvanstiphout

Active member
Local time
Yesterday, 22:38
Joined
Jan 22, 2016
Messages
222
That looks very promising. I can't wait to try it out.

I feed you a jellybean :)
 

arnelgp

..forever waiting... waiting for jellybean!
Local time
Today, 13:38
Joined
May 7, 2009
Messages
19,243
it work when you put timer on the pop-up, like this sample:
Code:
#If VBA7 Then
    Private Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr
#Else
    Private Declare Function GetActiveWindow Lib "user32" () As Long
#End If

Private Sub Form_Timer()
#If VBA7 Then
    Dim hnd As LongPtr
#Else
    Dim hnd As Long
#End If
hnd = GetActiveWindow
If hnd <> Me.Hwnd Then
    Me.Caption = "Outside"
Else
    Me.Caption = "Inside"
End If
End Sub
 

Gasman

Enthusiastic Amateur
Local time
Today, 06:38
Joined
Sep 21, 2011
Messages
14,299
I have to ask.... Why do you need to know if you clicked outside the form?
 

tvanstiphout

Active member
Local time
Yesterday, 22:38
Joined
Jan 22, 2016
Messages
222
I have to ask.... Why do you need to know if you clicked outside the form?
To mimic the MSFT behavior. As I wrote in first instance:
If you use that feature in Datasheet, and you click outside of it, it disappears.
 

sonic8

AWF VIP
Local time
Today, 07:38
Joined
Oct 27, 2015
Messages
998
The approach using a timer polling either GetActiveWindow or GetAsyncKeyState is probably the easiest to implement with VBA.
Nonetheless, I would also investigate using a mouse hook to monitor any mouse activity on the system. - This might be a dead end, but on first glance it looks much more elegant to me.
 

Josef P.

Well-known member
Local time
Today, 07:38
Joined
Feb 2, 2023
Messages
826
[mouse hook]
Maybe activate the hook only when the mouse leaves the edge of the form to the outside.
 

isladogs

MVP / VIP
Local time
Today, 06:38
Joined
Jan 14, 2017
Messages
18,221
Is it really important to allow the mouse to move outside the form or Access itself just so the filtering cannot run?
As a simple alternative, consider restricting the mouse cursor so it cannot leave the form. That is easily done
 

sonic8

AWF VIP
Local time
Today, 07:38
Joined
Oct 27, 2015
Messages
998
As a simple alternative, consider restricting the mouse cursor so it cannot leave the form. That is easily done
And then the user cannot use any other program/window until he completed selecting the filter settings?
I don't think users will be excited about this limitation.
 

Pat Hartman

Super Moderator
Staff member
Local time
Today, 01:38
Joined
Feb 19, 2002
Messages
43,275
To mimic the MSFT behavior. As I wrote in first instance:
I really hate using timer events. When you are developing, you have to be very careful to never have a form with a timer event open while you are modifying some other object or you risk losing your changes. I ended up adding code to automatically turn off all timer events when the user logged in was "me". I had a way to force them on when it was the timer that I was testing. Otherwise, it was far safer to just never let them run when I might be changing code.
 

CJ_London

Super Moderator
Staff member
Local time
Today, 06:38
Joined
Feb 19, 2013
Messages
16,612
One method I have used in the past is to add your form to another popup form (no or thin border, no record selectors, etc) leaving a margin of say 120 twips all the way around. Then use the sections mousemove event to determine if the mouse is within say 60 twips of the edge (represents 4 pixels) and if it is, close the form.

Not 100% reliable if the user moves the mouse too quickly, put this code in the detail mousemove event

if X <= 60 Or X >= InsideWidth - 60 or Y <= 60 Or X >= InsideHeight - 60 Then DoCmd.Close

More reliable

If X > 60 And X < InsideWidth - 60 and Y > 60 And Y< InsideHeight - 60 Then TimerInterval = 0 Else TimerInterval = 250

and in the timer event just

docmd.close

this works even if the popup is just over the desktop or another app although for your situation that won't be the case

Not tried it as I need to dig out the code, but it is possible if you make the popup transparent you can extend the borders (not sure if mousemove works with transparency)
 

bonds

New member
Local time
Today, 08:38
Joined
Mar 27, 2024
Messages
12
it work when you put timer on the pop-up, like this sample:
Code:
#If VBA7 Then
    Private Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr
#Else
    Private Declare Function GetActiveWindow Lib "user32" () As Long
#End If

Private Sub Form_Timer()
#If VBA7 Then
    Dim hnd As LongPtr
#Else
    Dim hnd As Long
#End If
hnd = GetActiveWindow
If hnd <> Me.Hwnd Then
    Me.Caption = "Outside"
Else
    Me.Caption = "Inside"
End If
End Sub
I do not understand how this code only would work. I attached it on my pop-up form timer event. Nothing happens when I click outside the pop-up. Please advise the solution.
 

Attachments

  • Multivalue_replacement11.zip
    439.1 KB · Views: 11

arnelgp

..forever waiting... waiting for jellybean!
Local time
Today, 13:38
Joined
May 7, 2009
Messages
19,243
i have numerous errors when opening your forms, (russian labels?).
anyway, try Adding Timer Interval (on design view) of your timer event (maybe 300).

here is a demo, open Form1 and click the button to open the pop-up form.
when the pop-up open, click anywhere on Form1 (but not on the button).
 

Attachments

  • db_popup.accdb
    508 KB · Views: 13
Last edited:

bonds

New member
Local time
Today, 08:38
Joined
Mar 27, 2024
Messages
12
i have numerous errors when opening your forms, (russian labels?).
anyway, try Adding Timer Interval (on design view) of your timer event (maybe 300).

here is a demo, open Form1 and click the button to open the pop-up form.
when the pop-up open, click anywhere on Form1 (but not on the button).
Thank you! After understanding your file it worked! I have to do some work to stop timer from repeating.
On top: Dim t=0
On load: t=0
And in timer event:
Code:
If t = 0 Then
#If Win64 Then
    Dim hnd As LongPtr
#Else
    Dim hnd As Long
#End If
hnd = GetActiveWindow
If hnd <> Me.hwnd Then
DoCmd.Close acForm, "ChoosePFTop"
t = 1
Else
t = 0
End If
End If
 

Attachments

  • Multivalue_replacement24.zip
    419.4 KB · Views: 11

bonds

New member
Local time
Today, 08:38
Joined
Mar 27, 2024
Messages
12
PS, For me it works even at the bottom. Maybe becuase I have a borderless pop-up form with a borderless pop-up child form. Also the code makes form corners square (not rounded). This is 100% replacement to MVF.
 
Last edited:

Users who are viewing this thread

Top Bottom