How to automatically resize or reposition controls on a form when the form is resized?

Viewed 518

So I'm trying to make my form fit to all monitors. Some have different display resolution and scale.

I can resize my form to fit to the display but all properties of its contents don't adjust to that new size.

What I want is if the form is scaled to fit to the display, the controls on the Form should adjust as well. Specifically properties like Left, Top, Width, Height, and so one, on every control.

The size could be scaled down or up.

1 Answers

It's possible to iterate through all of the controls on the form (mostly) programmatically, rather than having to explicitly adjust each control. You may have to put in some exceptions for some types of controls (such as timers, which I've put in the example), but generally you can use something like:

  Option Explicit

  Private Type ControlInfo_type
    Left As Single
    Top As Single
    Width As Single
    Height As Single
    FontSize As Single
  End Type
  Dim ControlInfos() As ControlInfo_type

Private Sub Form_Load()

  Dim ThisControl As Control
  
  ReDim Preserve ControlInfos(0 To 0)
  ControlInfos(0).Width = Me.Width
  ControlInfos(0).Height = Me.Height
  For Each ThisControl In Me.Controls
    ReDim Preserve ControlInfos(0 To UBound(ControlInfos) + 1)
    On Error Resume Next  ' hack to bypass controls with no size or position properties
    With ControlInfos(UBound(ControlInfos))
      .Left = ThisControl.Left
      .Top = ThisControl.Top
      .Width = ThisControl.Width
      .Height = ThisControl.Height
      .FontSize = ThisControl.FontSize
    End With
    On Error GoTo 0
  Next

End Sub

Private Sub Form_Resize()

  Dim ThisControl As Control, HorizRatio As Single, VertRatio As Single, Iter As Integer
  
  If Me.WindowState = vbMinimized Then Exit Sub
  
  HorizRatio = Me.Width / ControlInfos(0).Width
  VertRatio = Me.Height / ControlInfos(0).Height
  
  Iter = 0
  For Each ThisControl In Me.Controls
    Iter = Iter + 1
    On Error Resume Next  ' hack to bypass controls
    With ThisControl
      .Left = ControlInfos(Iter).Left * HorizRatio
      .Top = ControlInfos(Iter).Top * VertRatio
      .Width = ControlInfos(Iter).Width * HorizRatio
      .Height = ControlInfos(Iter).Height * VertRatio
      .FontSize = ControlInfos(Iter).FontSize * HorizRatio
    End With
    On Error GoTo 0
  Next
  
End Sub

I tested this with the default form with a CommandButton, Frame, Timer, and TextBox, and it seemed to work OK. You'll probably want to tune the limits on the minimum and maximum sizes for appearance, and my handling of the font is very crude; this could be optimized also. But perhaps this could be a starting point.

This code depends upon the controls iterating the same way each time, which could conceivably break. One way around this would be to use a Collection or other data structure with the name of the control as a key; when iterating in the .Resize event, each control would be looked up by name. Additional structure will be necessary if any of the controls are themselves arrays, and even more if controls are loaded or unloaded dynamically.

Related