Programmatically maximize a form vertically (-only)? (1 Viewer)

riktek

Member
Local time
Today, 15:30
Joined
Dec 15, 2023
Messages
77
The thread title. Is there a way to maximize a form, meaning a PopUp form in my case but perhaps also a form if in overlapping forms mode, vertically? Put otherwise, is there a way to get or set this window state for such a form?

By "vertically," I mean vertically-only, retaining the form's width.

One can do this by pressing Win + Shift + Up (and by dragging the top border of a window to the top of the screen), which I've found to be especially handy.

I'm just starting to think about doing this programmatically but the usual suspects don't seem to be up to the task. DoCmd.Maximize is perhaps vestigial in that it predates doing things like this, and it (and the DoCmd object generally) don't provide for more modern window states. I'm not certain there even is a window state property that exists for this. The PjWindowState constants include only maximized, minimized, and normal, and besides apply (via Application.WindowState, and then only for Excel, not Access) only to the application window, as opposed to the form or its window.

Barring a SysCmd of which I am not aware, approaches that come to mind include:
• SendKeys, with all its warts.
• Setting Form.WindowTop and Form.Height, likely with a Win32 call to get screen dimensions. Methinks an un-do with this approach would be circuitous, however.
• An as-yet unknown (to me, that is) window state setting in Win32 that I can get or set via Form.hWnd.

Or perhaps this is done otherwise and I'm unaware of it.

Any thoughts or recommendations, even about the best approach, would be most welcome.
 
Last edited:
Not sure I understand, but can you do this by code using the Form.Move method?
 
The thread title. Is there a way to maximize a form, meaning a PopUp form in my case but perhaps also a form if in overlapping forms mode, vertically? Put otherwise, is there a way to get or set this window state for such a form?

By "vertically," I mean vertically-only, retaining the form's width.

One can do this by pressing Win + Shift + Up (and by dragging the top border of a window to the top of the screen), which I've found to be especially handy.

I'm just starting to think about doing this programmatically but the usual suspects don't seem to be up to the task. DoCmd.Maximize is perhaps vestigial in that it predates doing things like this, and it (and the DoCmd object generally) don't provide for more modern window states. I'm not certain there even is a window state property that exists for this. The PjWindowState constants include only maximized, minimized, and normal, and besides apply (via Application.WindowState) only to the application window, as opposed to the form or its window.

Barring a SysCmd of which I am not aware, approaches that come to mind include:
• SendKeys, with all its warts.
• Setting Form.WindowTop and Form.Height, likely with a Win32 call to get screen dimensions. Methinks an un-do with this approach would be circuitous, however.
• An as-yet unknown (to me, that is) window state setting in Win32 that I can get or set via Form.hWnd.

Or perhaps this is done otherwise and I'm unaware of it.

Any thoughts or recommendations, even about the best approach, would be most welcome.
What an odd way of thinking about form sizes 🤔.

Access forms have always had two dimensions, both of which are fully changeable up to their maximum dimensions, along with two positions, again both fully changeable up to the constraints of the containing window.

The pertinent properties are "Width" and "Height". The refer to how wide the form is and how tall it is.

You can set them in the form's property sheet of course, and you can modify them independently or jointly in VBA using the not-at-all secret method DoCmd.MoveSize

More specifically, DoCmd.MoveSize accepts four arguments:

DoCmd.MoveSize (Right, Down, Width, Height)

Where
  • Right specifies the horizontal position of the left edge of the form as measured from the left edge of the window in which the form appears.
  • Down specifies the vertical position of the top edge of the form as measured from the top edge of the window in which the form appears.
  • Width specifies the width of the form as measured in twips.
  • Height specifies the height of the form as measured in twips.
When you want to adjust the height of a form dynamically, you can write a line of code that changes only the height, leaving the other three elements as they are. Or you can adjust both height and vertical position, if that suits the need better.

Now, choosing an event where you want that to be executed is another question. Perhaps the form's Current event?
 
Not sure I understand, but can you do this by code using the Form.Move method?
Yes, I neglected to mention that technique, but in the end it is simply another manner of setting Form.Top and Form.WindowHeight (and the method's other two parameters and the corresponding form properties), which I mentioned.
 
I don't see why what you are describing is a 'more modern window state'.
Anyway, suggest you do one of the following
1. Get the screen height in twips (intSH) then use DoCmd.MoveSize ,0, ,intSH
2. Save the form width as intFW then use DoCmd.Maximize then DoCmd.MoveSize , , , intFW. Turn off screen updating temporarily to prevent flicker
 
What an odd way of thinking about form sizes
LOL.

Actually, the specific context is PopUp forms in single form view having a text box bound to a memo field. An unbound example would be a custom Zoom form, the chief purpose of which is to get more real estate for a memo-bound control. A bound example might be a data entry form, needing to be in single form view to allow a subform for entry of related junction table data, and also having with a similar memo field.

In both cases, maximizing vertically instead of fully preserves the visual cue of the form being a popup, and also will increase the memo control's size further than otherwise, provided the memo control's vertical anchor property is suitably configured (= Both). The user can have the option to fully maximize the form (and thus the control) manually in the unlikely case maximizing vertically only is unsufficient.

Now, choosing an event where you want that to be executed is another question. Perhaps the form's Current event?

Essentially, the idea is to extend the vertical anchoring concept from controls to the form. So, my initial inclination would be to do this in the Load event. IIRC, Activate doesn't occur for PopUp forms (although this isn't documented). Current probably wouldn't work in the unbound case. As I think of it, Current also may not occur for PopUps. Second choice would be the Enter event of the control being first in the tab order.
DoCmd.MoveSize accepts four arguments
@MajP inquired about the Form.Move method, which accepts the same or similar four arguments, I believe. And, in my OP, I mentioned working through the Form.Top and Form.WindowHeight properties, which would seem to be the third way to skin the same cat. All of which I take as a confirmation that one of these three would be the preferred approach, which is quite helpful, and thanks.

This also seems to confirm that there aren't any unknown window state constants lurking in Win32 that one might exploit.
 
Last edited:
1. Get the screen height in twips (intSH) then use DoCmd.MoveSize ,0, ,intSH
Colin, thanks. This is just the direction I'm headed, especially after George's and @MajP 's input.
I don't see why what you are describing is a 'more modern window state'.
Simply because, to me, the additional window sizing options afforded in Windows 7 (I believe) by pressing Win or Win + Shift and an arrow key (maximize vertically, maximize horizontally, anchor left, anchor right) seem to be refinements of the rudimentary set of window state options (maximized, minimized, normal) that existed before their advent and as such can be regarded as windows states in their own right, modern additions to the rudimentary set, as it were. I admit this is a subjective impression, perhaps without nuance, but nevertheless.
 
At least partly the issue here is that Windows doesn't directly support a simple command to scale the window or its contents on one axis only. All of its "quick" tools (minimize, maximize, normalize) are bi-axial. When you say "vertically maximize" you are actually saying "distort the aspect ratio" - which is contrary to the Windows paradigm. You have to use direct coordinate-based instructions to move and resize the window for custom use. If that happens to involve some of the code found elsewhere on this forum to resize controls in that resized window, so be it. But the "simple" window tools don't want to distort the aspect ratio of your windows.
 
At least partly the issue here is that Windows doesn't directly support a simple command to scale the window or its contents on one axis only. All of its "quick" tools (minimize, maximize, normalize) are bi-axial. When you say "vertically maximize" you are actually saying "distort the aspect ratio" - which is contrary to the Windows paradigm. You have to use direct coordinate-based instructions to move and resize the window for custom use. If that happens to involve some of the code found elsewhere on this forum to resize controls in that resized window, so be it. But the "simple" window tools don't want to distort the aspect ratio of your windows.
Well, that's the question, really: Does a technique exist besides the obvious, of tinkering with coordinates and dimensions.

Regarding controls, the anchor properties are all that are necessary here. Really, only the memo control need resize with the form and it already does.

I would add it isn't a question of expecting simplicity - all conceivable solutions contemplate Win32 calls, after all, and a small set of helper functions. Rather, it's a question of what the available avenues are so I can get on with it. It won't be the first time.
 
Last edited:
For those interested, what I came up with is as follows.

By way of background, the Access methods and properties all place the form in question in, or relative to, the Access client area, or canvas. My objective, however, was to mimic Windows Aero effects and place it relative to the screen, so most everything depends on Win32 calls. It's helpful to know that x and y coordinates in Access are expressed in twips (1/1440 inch), while those in the Win32 API are expressed in the units of the display device, typically pixels. The latter are readily available via the Win32 API calls I employed, however.

I typically use this for popup forms, and for these I typically set Form.AutoCenter = True. The combined effect is that the form is centered on the screen and maximized from top to bottom. When I use a popup form, it typically is in continuous forms view, so this displays as many records as possible. When I use a popup in single form view, it typically has either a subform in continuous forms view or a memo field that benefits from being expanded. In those cases, it helps to set the .VerticalAnchor property for the SubForm control, any TabControl, or the memo field's TextBox, to acVerticalAnchorBoth so that the control maximizes vertically along with the form.

Any comments, quibbles, or suggestions are welcome.

The main VBA function, which can be called from Form.Load and is best conditioned on the form not being a subform:

Code:
Function VMaximize(ByRef frmThis As Access.Form) As Boolean
'   Function to vertically maximize an Access form.

    On Error Resume Next

    Const conProcName As String = "VMaximize"
    Const conPrintOffset As String = vbCrLf & vbTab
 
    Dim intPPI As Integer
 
    Dim hWnd As Long
 
    Dim LPixels As Long
    Dim RPixels As Long
    Dim WPixels As Long
    Dim HPixels As Long
 
    Dim lRect As RECT
 
    hWnd = frmThis.hWnd
    lRect = GetRECT(hWnd)
 
    intPPI = GetPPI
 
    LPixels = lRect.Left
    RPixels = lRect.Right
    WPixels = RPixels - LPixels
    HPixels = GetVERTRES - (intPPI / 4)
 
    'Debug.Print conProcName & ":" & conPrintOffset _
    & "RPixels = " & Right(Space(6) & RPixels, 6) & conPrintOffset _
    & "LPixels = " & Right(Space(6) & LPixels, 6) & conPrintOffset _
    & "WPixels = " & Right(Space(6) & WPixels, 6) & conPrintOffset _
    & "HPixels = " & Right(Space(6) & HPixels, 6)
 
    MoveWindow hWnd, LPixels, 0&, WPixels, HPixels, 0&
 
    VMaximize = (Err.Number = 0)
 
End Function    'VMaximize()


For help, I used the following:

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

#If VBA7 Then

    Private Declare PtrSafe Function GetDC Lib "user32" (ByVal hWnd As LongPtr) As LongPtr

    Private Declare PtrSafe Function GetDeviceCaps Lib "gdi32" (ByVal hdc As LongPtr, ByVal nIndex As Long) As LongPtr

    Private Declare PtrSafe Function GetWindowRect Lib "user32" Alias(ByVal hWnd As LongPtr, lpRect As rect) As LongPtr

    Private Declare PtrSafe Function MoveWindow Lib "user32" Alias "MoveWindow" ( _
        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 ReleaseDC Lib "user32" (ByVal hWnd As LongPtr, ByVal hdc As LongPtr) As LongPtr
                                                                     
#Else

    Private Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long

    Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal hDC As Long, ByVal nIndex As Long) As Long

    Private Declare Function GetWindowRect Lib "user32" (ByVal hWnd As Long, lpRect As RECT) As Long

    Private Declare Function MoveWindow Lib "user32" ( _
        ByVal hWnd As Long, _
        ByVal X As Long, _
        ByVal Y As Long, _
        ByVal nWidth As Long, _
        ByVal nHeight As Long, _
        ByVal bRepaint As Long) As Long

    Private Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, ByVal hDC As Long) As Long
 
#End If

Function GetPPI(Optional blnHorizontal As Boolean = True) As Long
'   Function to return a display's pixels per inch.

'   GetDeviceCaps index parameter constants for the item to be returned:
    Const LOGPIXELSX = 88       'Return horizontal pixels/inch.
    Const LOGPIXELSY = 90       'Return vertical pixels/inch.

    Dim hDC As Long

    hDC = GetDC(0&)             'Passing 0 gets the DC for the entire screen.

    If blnHorizontal Then       'Get horizontal ppi
        GetPPI = GetDeviceCaps(hDC, LOGPIXELSX)
    Else                        'Get vertical ppi
        GetPPI = GetDeviceCaps(hDC, LOGPIXELSY)
    End If
 
    ReleaseDC 0&, hDC
 
End Function    'GetPPI()


Function GetRECT(hWnd As Long) As RECT
    GetWindowRect hWnd, GetRECT
End Function    'GetRECT()


Function GetVERTRES() As Integer
'   Function to return a display's vertical resolution, in pixels.

    Const VERTRES = 10
    Dim hDC As Long
 
    hDC = GetDC(0&)
    GetVERTRES = GetDeviceCaps(hDC, VERTRES)
    ReleaseDC 0&, hDC

End Function    'GetVERTRES()
 
Last edited:

Users who are viewing this thread

Back
Top Bottom