Home > database >  Access VBA - ".MoveSize" or ".Move" for a popup form positioning
Access VBA - ".MoveSize" or ".Move" for a popup form positioning

Time:12-03

I am new to VBA therefore please excuse me in advance if my question is silly. That said, I have created a very simple on click button event, which is supposed to move my popup form to the top left corner of the screen. The function that I used was:

Private Sub Command1_Click()
    DoCmd.MoveSize(0 ,0)
End Sub

Initially it worked, but then I noticed that if my popup form is positioned on my second monitor and use this function it will send back the popup form to the top left corner of my primary monitor. Is there a way to somehow tell the function to send the form to the top left corner to whichever monitor the form is being opened in?

As this hasn't worked I tried a different idea where I will use a function to use the ".Move" property of the form. I came up with this:

Private Sub Command1_Click()
    Form.Move(0, 0)
End Sub

Sadly this didn't work either, as it seems that the "0, 0" coordinates are relative to wherever the Access Window is positioned on the screen and not the top left corner of the monitor.

Is this some sort of a limitation from Access VBA or do you think it is doable using some other techniques? I would be really grateful to hear what you think on this problem. Thank you in advance!

CodePudding user response:

While this seems trivial, unfortunately, it isn't, and we're going to need to use a fair amount of WinAPI. That makes it really hard for beginners.

We need a couple of things:

  1. We need to be able to determine on which monitor the form is
  2. We need to be able to determine where that monitor is in the "virtual screen" (think about positioning monitors relative to eachother)
  3. We need to be able to determine the size of the current window in pixels
  4. We need to be able to position the form on the "virtual screen".

For that, we need a couple of declarations. These are best kept on separate modules, but if you're 100% sure they will only be used on this form, they can go on the form too.

First, the type and value declarations:

'https://docs.microsoft.com/en-us/windows/win32/api/windef/ns-windef-rect
Public Type RECT
    left As Long
    top As Long
    right As Long
    bottom As Long
End Type

'https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-monitorinfo
Public Type MONITORINFO
    cbSize As Long
    rcMonitor As RECT
    rcWork As RECT
    dwFlags As Long
End Type

'Either look this one up by Googling, or create a C   program that references winuser.h and print it
Public Const MONITOR_DEFAULTTONEAREST = &H2

Then, the function declarations:

'https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmonitorinfow
Public Declare PtrSafe Function GetMonitorInfoW Lib "User32.dll" (ByVal hMonitor As LongPtr, ByRef lpmi As MONITORINFO) As Boolean

'https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-monitorfromwindow
Public Declare PtrSafe Function MonitorFromWindow Lib "User32.dll" (ByVal hWnd As LongPtr, ByVal dwFlags As Long) As LongPtr

'https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-movewindow
Public Declare PtrSafe Function MoveWindow Lib "User32.dll" (ByVal hWnd As LongPtr, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal bRepaint As Boolean) As Boolean

'https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowrect
Public Declare PtrSafe Function GetWindowRect Lib "User32.dll" (ByVal hWnd As LongPtr, ByRef lpRect As RECT) As Boolean

And then, on the form, putting it all to work:

Private Sub Command0_Click()
    Dim mi As MONITORINFO
    Dim monitor As LongPtr
    Dim myrect As RECT
    'Get the current size and position of the window
    GetWindowRect Me.hWnd, myrect
    'Determine which monitor it is on
    monitor = MonitorFromWindow(Me.hWnd, MONITOR_DEFAULTTONEAREST)
    'Make sure WinAPI knows the size of the MONITORINFO struct we're working with
    mi.cbSize = LenB(mi)
    'Get the monitor info
    GetMonitorInfoW monitor, mi
    'Move the window to the top right, keep width and height equal to the current values
    MoveWindow Me.hWnd, mi.rcMonitor.left, mi.rcMonitor.top, myrect.right - myrect.left, myrect.bottom - myrect.top, True
End Sub

Unfortunately, that's quite a lot more code and more complicated concepts than DoCmd.MoveSize(0 ,0), but I do not know of a simpler approach. VBA doesn't really have any support for multiple monitors, so you'll often have to go to WinAPI to account for them.

  • Related