excelvbauserform

How can I determine the usable area of an Excel VBA userform so I can resize it to fit the controls?


If I create an Excel VBA userform form which dynamically generates a variable number of controls, how can I determine the usable area of the form so I can resize the form to fit the controls?

A screenshot is attached below, followed by a code sample, but the last few lines of code do not work.

I am able to write my own auto-size code for UserForm_Initialize(), but this isn't possible if I can't find the usable width and height of the form. There is always a discrepancy which no doubt includes the sizes of the borders, shadows, titlebar, etc.

I do understand VBA is disorganized with various measurement scales such as pixels, twips, inches, etc. So it would be helpful if any answer specifies the scale being used, so I can call the correct conversion functions.

I did find this post about the VBA coordinate systems, which helps but it doesn't answer my question: https://www.reddit.com/r/vba/comments/1arzvx8/coordinate_systems_in_vba_userform_controls/

enter image description here

Private Sub UserForm_Initialize()
    
    Dim ctls        As MSForms.Controls
    Dim ctl         As MSForms.Control
    Dim coll        As VBA.Collection
    Dim ctlCount    As Integer
    Dim colCount    As Integer
    Dim x           As Single
    Dim y           As Single
    Dim w           As Single
    Dim h           As Single
    Dim i           As Integer
    
    'Settings.
    colCount = 5
    w = 24
    h = 24
    
    'Get the objects.
    Set ctls = Me.Controls
    Set coll = New VBA.Collection
    
    'Add the buttons to a collection.
    ctlCount = ctls.Count
    For i = 0 To ctlCount - 1
        For Each ctl In ctls
            If ctl.TabIndex = i Then
                coll.Add ctl
            End If
        Next
    Next
    
    'Align the buttons.
    i = 0
    Do
        If i < ctlCount Then
            y = y + 1
            Do
                x = x + 1
                If x <= colCount Then
                    i = i + 1
                    Set ctl = coll.Item(i)
                    ctl.Left = (x - 1) * w
                    ctl.Top = (y - 1) * h
                    ctl.Width = 24
                    ctl.Height = 24
                Else
                    Exit Do
                End If
            Loop
            x = 0
        Else
            Exit Do
        End If
    Loop
    
    'Adjust the form size.
    Me.Width = (x + 1) * w      '### This does not work. ###
    Me.Height = (y + 1) * h     '### This does not work. ###
    
End Sub

Solution

  • As already written in the comments, the properties you are looking for are InsideHeight and InsideWidth.

    I reworked you code a little bit and this is what I came up with. Note that I put the resizing into a separate routine so that you can call it whenever you are done with creating controls "on the fly".

    Private Sub UserForm_Initialize()
        CreateControls ... ' If you want to create some controls first
        ResizeControls
    End Sub
    
    Private Sub ResizeControls
        Const ColCount = 5
        Const w As Double = 24
        Const h As Double = 24
        
        Dim i As Long
        ReDim ctrlArr(0 To Me.Controls.Count - 1)
        Dim ctrl As Control
        
        For i = 0 To Me.Controls.Count - 1
            Set ctrlArr(Me.Controls(i).TabIndex) = Me.Controls(i)
        Next
        
        Dim row As Long, col As Long
        For i = LBound(ctrlArr) To UBound(ctrlArr)
            Set ctrl = ctrlArr(i)
            
            row = i \ ColCount
            col = i Mod ColCount
            Debug.Print i, row & "/" & col
            
            With ctrl
                ' .Caption = i  ' Just for test, will show the index as text
                .Left = col * w
                .Top = row * h
                .Width = w
                .Height = h
            End With
        Next
        
        Dim rowcount As Long
        rowcount = ((UBound(ctrlArr) - 1) \ ColCount) + 1
        
        ' Difference between width and usable width resp. height and usable height
        Dim dx As Double, dy As Double
        dx = Me.Width - Me.InsideWidth
        dy = Me.Height - Me.InsideHeight
        
        'Adjust the form size.
        Me.Width = ColCount * w + dx
        Me.Height = rowcount * h + dy
        
    End Sub
    

    Design Time (9 buttons, chaotic on purpose):

    enter image description here

    At runtime:

    enter image description here