8
\$\begingroup\$

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.

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 -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:

SimpleView 400x500

Or this:

Set view = New SimpleView
view.Height = 400
view.Width = 200
view.Show

To get that:

SimpleView 200x400

\$\endgroup\$
4
  • \$\begingroup\$ And your question is...? Why did you put this code up for review? Do you think it can't be better (and are looking for confirmation), do you think it should be better (and are looking for alternatives)... \$\endgroup\$
    – Pimgd
    Jul 29 '14 at 12:18
  • 1
    \$\begingroup\$ "what I have works pretty well with what I'm using it for, I'd like to know if it could be done better" - can it? \$\endgroup\$ Jul 29 '14 at 12:28
  • \$\begingroup\$ Just to be clear, this is a UserForm, not an Access Form, correct? \$\endgroup\$
    – RubberDuck
    Jul 29 '14 at 12:45
  • \$\begingroup\$ @ckuhn203 correct, it's Excel VBA ;) \$\endgroup\$ Jul 29 '14 at 12:46
6
\$\begingroup\$

I really like this method of declaring a bitwise enum.

Public Enum AnchorEdges
    LeftAnchor = 2 ^ 0
    TopAnchor = 2 ^ 1
    RightAnchor = 2 ^ 2
    BottomAnchor = 2 ^ 3
    AnchorAll = LeftAnchor + TopAnchor + RightAnchor + BottomAnchor
End Enum

I find it much preferable to the way I usually see it done.

Public Enum BitWiseEnum
    SomeValue = 1
    SomeValue = 2
    SomeValue = 4
    SomeValue = 8
 End Enum

But you don't need all of this.

If (anchor And BottomAnchor) = BottomAnchor Then

The condition can be written simply as

If (anchor And BottomAnchor) Then

I would recommend leaving a small comment alerting the unwary maintainer that it is a bitwise And not a logical And though. I don't imagine too many VBA Maintainers will understand this code at a glance.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.