Going down the rabbit hole, I wanted to be able to change the size of a form, and not have to worry about the layout of the controls.
vba doesn't support user-resizeable forms, but forms still have a Resize
event that fires when a form's size is programmatically changed.
I'm leveraging this event handler to set up my automatic layout, like this:
Private Sub BindControlLayouts() Dim backgroundImageLayout As New ControlLayout backgroundImageLayout.Bind Me, BackgroundImage, AnchorAll Dim closeButtonLayout As New ControlLayout closeButtonLayout.Bind Me, CloseButton, BottomAnchor + RightAnchor Dim itemsListLayout As New ControlLayout itemsListLayout.Bind Me, ItemsList, AnchorAll Dim addButtonLayout As New ControlLayout addButtonLayout.Bind Me, AddButton, RightAnchor Dim editButtonLayout As New ControlLayout editButtonLayout.Bind Me, EditButton, RightAnchor Dim showDetailsButtonLayout As New ControlLayout showDetailsButtonLayout.Bind Me, ShowDetailsButton, RightAnchor Dim deleteButtonLayout As New ControlLayout deleteButtonLayout.Bind Me, DeleteButton, RightAnchor layoutBindings.Add closeButtonLayout, _ backgroundImageLayout, _ itemsListLayout, _ addButtonLayout, _ editButtonLayout, _ showDetailsButtonLayout, _ deleteButtonLayout End Sub Private Sub UserForm_Resize() Application.ScreenUpdating = False If Me.Width < minWidth Then Me.Width = minWidth If Me.Height < minHeight Then Me.Height = minHeight Dim layout As ControlLayout For Each layout In layoutBindings layout.Resize Me Next Application.ScreenUpdating = True End Sub
That code is reviewable as part of this post, and it's the client code of a class I'd like reviewed here:
ControlLayout class module
There's no magic, I haven't implemented a wpf-like automagic layout. But what I have works pretty well with what I'm using it for, I'd like to know if it could be done better:
Option Explicit
Public Enum AnchorEdges
LeftAnchor = 2 ^ 0
TopAnchor = 2 ^ 1
RightAnchor = 2 ^ 2
BottomAnchor = 2 ^ 3
AnchorAll = LeftAnchor + TopAnchor + RightAnchor + BottomAnchor
End Enum
Private anchors As AnchorEdges
Private margins As SideMargins
Private size As ControlSize
Private formSize As ControlSize
Private boundControl As Control
Public Sub Bind(form As UserForm, formControl As Control, anchor As AnchorEdges)
anchors = anchor
formSize.Height = form.InsideHeight
formSize.Width = form.InsideWidth
size.Height = formControl.Height
size.Width = formControl.Width
If (anchor And BottomAnchor) = BottomAnchor Then
margins.BottomMargin = formSize.Height - formControl.Top - formControl.Height
End If
If (anchor And LeftAnchor) = LeftAnchor Then
margins.LeftMargin = formControl.Left
End If
If (anchor And RightAnchor) = RightAnchor Then
margins.RightMargin = formSize.Width - formControl.Left - formControl.Width
End If
If (anchor And TopAnchor) = TopAnchor Then
margins.TopMargin = formControl.Top
End If
Set boundControl = formControl
End Sub
Public Sub Resize(ByVal form As UserForm)
formSize.Height = form.InsideHeight
formSize.Width = form.InsideWidth
layout boundControl
End Sub
Public Sub layout(ByVal formControl As Control)
If (anchors And TopAnchor) = TopAnchor Then
If (anchors And BottomAnchor) = BottomAnchor Then
formControl.Height = formSize.Height - formControl.Top - margins.BottomMargin
End If
ElseIf (anchors And BottomAnchor) = BottomAnchor Then
formControl.Top = formSize.Height - formControl.Height - margins.BottomMargin
End If
If (anchors And LeftAnchor) = LeftAnchor Then
If (anchors And RightAnchor) = RightAnchor Then
formControl.Width = formSize.Width - formControl.Left - margins.RightMargin
End If
ElseIf (anchors And RightAnchor) = RightAnchor Then
formControl.Left = formSize.Width - formControl.Width - margins.RightMargin
End If
End Sub
I can just do this:
Set view = New SimpleView
view.Height = 400
view.Width = 500
view.Show
And get that:
Or this:
Set view = New SimpleView
view.Height = 400
view.Width = 200
view.Show
To get that: