Pop up forms not "stacking" in the right order

Bennet

Member
Local time
Today, 23:46
Joined
May 23, 2020
Messages
38
Hi, fellow Access enthusiasts.

I have a front end database which runs with a maximised form as it's main interface.

Sometimes, I open a "pop-up" form in a window which opens in front of the main form - all fine so far.

Then the first pop-up form generates a second pop up form which gives the user some further info they have requested. This second pop-up should open in front of the first one - and it always did used to do that until a few months ago when it began opening, I think, behind the first pop-up. Both pop ups are in dialogue mode, so they lock interaction with the rest of the database until you close them. This is necessary.

Because you cannot see the secondary pop-up, this effectively locks up the screen. You can solve it by clicking around randomly and/or switching to another window completely, and coming back to the database, whereupon it may decide to show the correct form. You can always get it back after a bit of clicking around but it's not clear why.

Any idea why this has started happening and what I can do about it? It never used to do this and I didn't change anything. Happening for multiple users at my company.

My assumption is that it is behind the first form, but it's not impossible that it's off screen completely or otherwise invisible.

temp.png
 
Focusing on your final paragraph…

Popup forms are displayed where they were last saved in design view. So if you saved them on a secondary monitor, that’s where they will reopen. If then opened on a workstation with only one monitor, they will indeed be off screen.

Suggest you reopen the errant forms in design view and save in the correct location
 
I use bit of code to check which monitor the mouse pointer is on and move the popup to that monitor setting it to appear wherever you want

On my phone but can post it when back at my desk if of interest
 
Unless you actually need to see multiple forms at once, you might consider hiding the calling form so only the currently active form is visible. If necessary, you just add:
Me.Visible
As the first statement after the OpenForm which opens the modal popup.
 
I use bit of code to check which monitor the mouse pointer is on and move the popup to that monitor setting it to appear wherever you want

On my phone but can post it when back at my desk if of interest

I like the sound of this and would be grateful if you are willing to share, for general purpose use.

Some further experimentation indicates that the problem in this case is definitely a window stacking issue, rather than the form opening unnoticed on a different monitor.
 
Unless you actually need to see multiple forms at once, you might consider hiding the calling form so only the currently active form is visible. If necessary, you just add:
Me.Visible
As the first statement after the OpenForm which opens the modal popup.
Could probably solve it by hiding the parent forms. Aiming to keep the parent forms visible for reference if possible.

Tried adding Me.Visible = True to the on-load code of the form which didn't make any difference. Which makes sense, since the form is visible, it just isn't "on top".
 
I dare say, if you can get the window hwnd, there will be some command to bring to the forefront?

ChatGPT (untested)

If you're just working within Access and want to ensure a form is on top of other Access forms, you can use:


Code:
DoCmd.SelectObject acForm, "YourFormName", True
DoCmd.OpenForm "YourFormName", acNormal
Bring Access Window to Front Using Windows API
If you need to bring Access itself to the front (in case the user has switched to another application), you can use the SetForegroundWindow API.

This brings focus to the form within Access, but does not bring Access to the front of other applications.
Code:
Private Declare PtrSafe Function SetForegroundWindow Lib "user32" (ByVal hWnd As LongPtr) As Long
Private Declare PtrSafe Function FindWindowA Lib "user32" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr

Sub BringAccessToFront()
    Dim hWnd As LongPtr
    hWnd = Application.hWndAccessApp
    SetForegroundWindow hWnd
End Sub

Code:
Sub ShowMyForm()
    Call BringAccessToFront
    DoCmd.OpenForm "YourFormName", acNormal
    DoCmd.SelectObject acForm, "YourFormName", True
End Sub
 
Last edited:
There is one problem you may have in solving this.
Because popup forms are 'above' the application interface, they are never considered as the active form by Access and cannot be referenced as such. This may make it harder to handle your issue with code
 
Pretty sure this will work but still not on my computer

Set the popup form to modal and in the forms open event set modal = false
 
The problem as I understand it is that popups can appear behind another popup - it is not high enough up the z- order. Opening as modal guarantees it will be at the top. Setting it to false simply disables the ‘user restriction’ to that form until it is closed. The OP doesn’t want that restriction
Then the first pop-up form generates a second pop up form which gives the user some further info they have requested. This second pop-up should open in front of the first one - and it always did used to do that until a few months ago
 
Aiming to keep the parent forms visible for reference if possible.
I think that in terms of designing a user interface to manage a process, it is a flaw if the user must return to a previously visible UI component to complete a current task. Even if you solve your z-order problem, the current task UI opens on top of and obscures the data to consult, forcing the user to grab the mouse and work harder.
Better IMO would be a main form that presents overall task progress and state. This main form might then open a sequence of subforms in a subform control, and/or be supported by a series of navigable tabs.
Or as Pat suggests in #4, complete the master task and close/hide its UI. Then present a sub-task UI (or sequence of) that in each discrete step expresses whatever the user needs to complete that step.
 
I like the sound of this and would be grateful if you are willing to share, for general purpose use.
put this into a module called say modMonitors

in your popup form load event put placeform me

This is intended to place the form where the bottom left is at the cursor position - but then adjusted if required to fit on the monitor if the cursor is too close to the top or right for the dimensions of the form.

I've extracted it from other code in my app so should work as is. However I've not tested if the form is wider or taller than the monitor so you may need to make an adjust to default top and left to top left of the monitor.

Code:
Option Compare Database
Option Explicit

Private Type POINTAPI
    X As Long
    Y As Long
End Type

Private Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

Private Type MONITORINFO
    cbSize As Long
    rcMonitor As RECT
    rcWork As RECT
    dwFlags As Long
End Type

Private Declare PtrSafe Function GetCursorPos Lib "USER32" (lpPoint As POINTAPI) As Long
Private Declare PtrSafe Function GetSystemMetrics32 Lib "USER32" Alias "GetSystemMetrics" (ByVal nIndex As Long) As Long

Private Declare PtrSafe Function MoveWindow Lib "USER32" (ByVal hWnd As LongPtr, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal bRepaint As Long) As Long
Private Declare PtrSafe Function GetWindowRect Lib "USER32" (ByVal hWnd As LongPtr, lpRect As RECT) As Long
 
Private Declare PtrSafe Function EnumDisplayMonitors Lib "USER32" (ByVal hdc As LongPtr, ByVal lprcClip As LongPtr, ByVal lpfnEnum As LongPtr, ByVal dwData As LongPtr) As Boolean
Private Declare PtrSafe Function GetMonitorInfo Lib "USER32" Alias "GetMonitorInfoA" (ByVal hMonitor As LongPtr, ByRef lpmi As MONITORINFO) As Boolean

Private monitors() As MONITORINFO

Private monitorCount As Long
'___________________________________________________________________________________________________________
Sub PlaceForm(frm As Form)
Dim PT As POINTAPI
Dim i As Long
Dim mRect As RECT
Dim fRect As RECT
Dim adjLeft As Long
Dim adjTop As Long

    'get monitor metrics
    monitorCount = 0
    EnumDisplayMonitors 0, 0, AddressOf EnumMonitorsProc, 0
    
    'get cursor position
    GetCursorPos PT
    
    'determine which monitor the cursor is on
    For i = 1 To monitorCount
        
        mRect = monitors(i).rcMonitor
        
        If PT.X >= mRect.Left And PT.X < mRect.Right And PT.Y >= mRect.Top And PT.Y < mRect.Bottom Then Exit For
        
    Next i
    
    'now adjust form position to fit on the monitor - not tested for form being wider or taller than the monitor
    GetWindowRect frm.hWnd, fRect
    If PT.X + fRect.Right - fRect.Left < mRect.Right Then adjLeft = PT.X Else adjLeft = mRect.Right - (fRect.Right - fRect.Left)
    If PT.Y - fRect.Bottom + fRect.Top < mRect.Top Then adjTop = mRect.Top Else adjTop = PT.Y - fRect.Bottom + fRect.Top
    
    MoveWindow frm.hWnd, adjLeft, adjTop, fRect.Right - fRect.Left, fRect.Bottom - fRect.Top, True
   
    
End Sub

Private Function EnumMonitorsProc(ByVal hMonitor As LongPtr, ByVal hdcMonitor As LongPtr, ByRef lprcMonitor As RECT, ByVal dwData As LongPtr) As Boolean
ReDim Preserve monitors(1 To monitorCount + 1) As MONITORINFO

Dim mi As MONITORINFO
mi.cbSize = LenB(mi)
GetMonitorInfo hMonitor, mi

monitors(monitorCount + 1) = mi
monitorCount = monitorCount + 1

EnumMonitorsProc = True
End Function
 

Users who are viewing this thread

Back
Top Bottom