Restoring popup to same position

Over the years I have many times tried to add the functionality of restoring a popup to the same location/size in which it was closed. But so far this always came with a risk with multi monitor setup. Say a user had the app on the left screen and placed the popup on the right screen. If he then moved the app to the right screen, well then the popup would open to the right of the screen, and thus be off screen with no way for the user to restore it to a place visible to the user.

While the possibility of it happening might be remote, I never wanted to take that risk. But recently I came across a solution. Using the api MonitorFromWindow to ensure that the form is actually ON a monitor. If the API call returns 0 that means the form is not found on any monitor, and when that happens I can return the form to be centered.

Private Declare Function apiMonitorFromWindow Lib "User32.dll" Alias "MonitorFromWindow" (ByVal hWnd As Long, ByVal dwFlags As Long) As Long
Public Function GetMonitorHandleFromWindow(hWnd As Long, Optional ReturnValueIfNotOnScreen As guiMonitorFromWindow = MONITOR_DEFAULTTONULL) As Long 
   'Returns the monitor ID based on which monitor has the largest intersection with the window
   GetMonitorHandleFromWindow = apiMonitorFromWindow(hWnd, ReturnValueIfNotOnScreen)
End Function

But my troubles weren’t really done there. Initially I wanted to “stay within Access” as much as possible, and just wanted to use form.WindowLeft to get the forms position. However the form.WindowLeft is limited to an integer, and this means if you move to form far to the right (beyond 32000) then it overflows and becomes negative.

Jack Leach wrote some GUI handling code as a class module a while ago which overcomes this part of the problem, relying on windows API calls. So I incorporated his code and believe I finally have a solution I trust to produce a good user experience in all scenarios.

I did take it one step further and added a couple of checks. I.e. if the application monitor handle has changed since the form was last opened, then don’t make any changes (i.e. open the form to design time defaults), which for me means AutoCenter=true.

 

I have tested the solution in various scenarios,  including 3 monitor setup, cases where I move the access application around, add-remove monitors in between closing and opening and such. In my tests, I have used Popup=true, and Autocenter=true.

You can find my modified code in a attachment at the bottom of this post, I have added it to the the GUI class module that Jack Leach designed, with his permission. You can find the original version at utteraccess  Original GUI class module. It relies so heavily on this functions that I felt it made the most sense incorporate it into that module, rather than adding my own module.

So from your popup form, you call the code like so:

Private Sub Form_Close()
   GUI.StoreFormPosition Me
End Sub

Private Sub Form_Load()
   GUI.RestoreFormPosition Me
End Sub

and what is does can be seen below:

Public Sub StoreFormPosition(frm As Form)
   'Get the location of the form and the access window
      Dim plFormWindow As GUI_PLACEMENT
      GUI.WindowPlacement frm.hWnd, plFormWindow, ContainerScreen
   
   'Save form values to registry
      SaveSetting CurrentProject.Name, frm.Name, "Left", plFormWindow.Left
      SaveSetting CurrentProject.Name, frm.Name, "Top", plFormWindow.Top
      SaveSetting CurrentProject.Name, frm.Name, "Width", plFormWindow.Width
      SaveSetting CurrentProject.Name, frm.Name, "Height", plFormWindow.Height
      SaveSetting CurrentProject.Name, frm.Name, "LastApplicationMonitorHandle", GUI.GetMonitorHandleFromWindow(Application.hWndAccessApp)
   
End Sub
Public Sub RestoreFormPosition(frm As Form)
   
   Dim plFormWindowOld As GUI_PLACEMENT
   Dim plFormWindowRestore As GUI_PLACEMENT
   Dim LastApplicationMonitorHandle As Long
   
   'Note whatever width and height the form opened with, into a placement type
      GUI.WindowPlacement frm.hWnd, plFormWindowOld, ContainerScreen

   
   LastApplicationMonitorHandle = GetSetting(CurrentProject.Name, frm.Name, "LastApplicationMonitorHandle", 0)
   If LastApplicationMonitorHandle <> 0 Then 'if 0, then no settings are stored yet
      With plFormWindowRestore
         .Left = GetSetting(CurrentProject.Name, frm.Name, "left", plFormWindowOld.Left)
         .Top = GetSetting(CurrentProject.Name, frm.Name, "top", plFormWindowOld.Top)
         .Width = GetSetting(CurrentProject.Name, frm.Name, "Width", plFormWindowOld.Width)
         .Height = GetSetting(CurrentProject.Name, frm.Name, "Height", plFormWindowOld.Height)
      End With
      'Has the App monitor changed since form location was stored (user moved the application to different monitor)
      If GUI.GetMonitorHandleFromWindow(Application.hWndAccessApp) <> LastApplicationMonitorHandle Then
         'We do nothing. Leave form as it was opened by access itself (i.e. default settings)
      Else
         'Move form to where the user closed it
         GUI.SetWindowPlacement frm.hWnd, plFormWindowRestore, ContainerScreen
      End If
   End If
   'Finally check that the form is witin visible screen
   If GUI.GetMonitorHandleFromWindow(frm.hWnd) = 0 Then
      'Form is off screen, center it
      GUI.SetWindowGeneralPlacement frm.hWnd, PlaceXCenter, placeYCenter
   End If
End Sub

And the full download sample for download is here:

[download id=”675″]

If you end up using this solution, please take the time to leave a comment here.

5 comments on “Restoring popup to same position
  1. Sasha says:

    Hello Anders,
    First off all,
    Thank you for many usefull tips on this and many other topics.
    I have question that relate to this topic and if I missed the clue, please forgive me for wasting your time.
    Question : How to make popup form to follow the main application window and to stay in the application boundries?
    What I’,m trying to do is when you move main application window to another monitor (say you have two of them), I want to popup forms to open inside of main application window wherever main window may be.
    Maybe the answer is here, but I dont see it.

    Thanks in advance.

  2. Sasha says:

    Hi Anders,
    I may missed the point in this topic so sorry for wasting your time in that case.
    Anyway, I want popup form to open Inside of main application window even if the main application window is moved to another monitor. How can i do this?

    • TheSmileyCoder says:

      Thank you. I think the GUI class supports this, but I don’t have the answer just now off the top of my head.

      • kostas says:

        Hello TSC!
        GUI class Rock’s! Thank you for sharing. My problem is solved by GUI class.
        Every single pop up form now opens in main application window. Thanks again.

  3. Dale Fye says:

    Smiley,

    This works great. Thanks for putting this all together and sharing it!

    Dale

Leave a Reply to TheSmileyCoder Cancel reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.