如何动态地使控件在 MS Access 窗体上居中(相对位置)?

How to Dynamically keep controls centered (relative position) on an MS Access form?

我在 Access 2013 中工作,有许多控件(列表框、按钮等)我想在调整窗体大小时将它们作为一个组保持居中。

锚定不会完成我正在寻找的东西,因为我不想将控件锁定到 top/bottom/left/right。我希望他们留在中心。

简单地在表单的调整大小事件中使用 me.mycontrol.left = myform.Width/2 这样的代码并不能满足我的要求,因为它将各个控件对齐到中心。我希望控件组居中。

有办法吗?

编辑:这是一个示例,可以使这一点更清楚。假设我有一个 100 x 100 的表单,上面有两个按钮。这些按钮有 20 个单位高,并且 spaced 相隔 10 个单位。他们将担任以下职务:

Button1.Top = 25 (10 个单位 space 从 45 开始) Button2.Top = 55

如果将窗体大小调整为 200 x 200,控件将具有以下位置:

Button1.Top = 75 (10 单位 space 从 95 开始) Button2.top = 105

理想情况下,我喜欢将它变成一个模块,我只需将一个表单传递给它,它会获取每个控件的原始位置并计算新位置。

编辑 2:

这是一个失败的尝试,使用我的真实代码,基于 Krish 的想法:

Private Sub Form_Resize()

Dim resizeFactor As Double

resizeFactor = Me.WindowWidth / Me.Width

Me.lstModule.Left = Me.lstModule.Left * resizeFactor
Me.ctlSubform.Left = Me.ctlSubform.Left * resizeFactor
Me.Box6.Left = Me.Box6.Left * resizeFactor

End Sub

据我所知,MS Access 中没有任何布局 "containers"(tabular/stacked 视图除外)。你最好的办法是在你的 components.Tag 属性 中添加一个字符串并循环遍历必须重新对齐的组件

像这样:

        Dim iCtl As control
        For Each iCtl In Me.Form
            If iCtl.Tag = "resize" Then
                On Error Resume Next
                Debug.Print "control resizing: " & iCtl.name
                iCtl.width = iCtl.width * resizeFactor
                iCtl.Height = iCtl.Height * resizeFactor
                'left top whatever you want to re align
            End If
        Next iCtl

我可以使用元代码:

  • 用文本标记标记组中的所有控件('Tag' 属性)
  • 遍历表单上的所有控件,并为具有匹配标签的所有控件计算表单上控件的最左、最上、最右和最下位置(右=左+宽度等)
  • 这是群组'window'
  • 现在再次遍历表单,通过相对于组 'window'
  • 计算的 X/Y 偏移量来偏移控件

或者,我想,一些真正的代码:-)

    Public Function GetControlsWindowSize(tag As String)
    Dim f As Form
    Dim c As Control
    Dim GrpLeft As Long
    Dim GrpRight As Long
    Dim GrpTop As Long
    Dim GrpBottom As Long

        For Each c In f.Controls
            If c.Properties.Item("tag") = tag Then
                If GrpLeft = 0 Or GrpLeft > c.Left Then GrpLeft = c.Left
                If GrpRight = 0 Or GrpRight < c.Left + c.Width Then GrpRight = c.Left + c.Width
                If GrpTop = 0 Or GrpTop > c.Top Then GrpTop = c.Top
                If GrpBottom = 0 Or GrpBottom < c.Top + c.Height Then GrpBottom = c.Top + c.Height
            End If
        Next
    End Function

我认为锚定实际上就是答案。您只需围绕控件创建一个布局网格并像这样设置锚点:

_____________________|___stretch down____|___________________
stretch across top___|___your controls___|stretch across top
_____________________|___stretch down____|___________________

这样您的控件将始终位于 form/subform 的中间。

编辑:截图

编辑:添加了关于边框的信息

添加边框可能会很痛苦,但在某种程度上,这是可能的。您可以通过设置网格线颜色、将网格线样式设置为按钮的实体(默认为透明)并添加一些填充来实现。在下面的示例中,我将第一个按钮的网格线样式设置为 LEFT、RIGHT 和 TOP 的实体,并将这些边的填充设置为 0.1"。如果您继续使用类似的方式,您的结果将如下所示:

我意识到这已经晚了很多年,但我有一个替代 VBA 解决方案给你。我在尝试了许多其他人的代码后写出了这个,但对他们的工作方式并不满意。

我想要的是让所有控件都在表单(顺便说一下弹出表单)中居中。然而,我不希望它们都在中心混在一起,我希望它们是 "Grouped",并且让控件组在表单中居中,而不是每个单独的控件居中。

我需要的另一个条件是当 window 最大化时需要让控件居中,或者在较小的 window 中。当用户调整表单大小时,控件需要在表单中动态居中。

我做了一个sub过程,需要在Private Sub Form_Resize()事件和Private Sub Form_Current()事件中调用。我正在使用 Access 2010。

Private Sub Form_Resize()
'Should run every time the form is resized
    Call CenterControls
End Sub

Private Sub Form_Current()
  'Will run when the form is completing its initialization
   DoCmd.Maximize   'Maximizes the form when first initialized. Omit if required.
   Call CenterControls
End Sub

这就是神奇的地方。

Sub CenterControls()

'Find the control that has the farthest left position, and the one with the farthest right position.
'That will give us the total distance of our buttons. We will then have to compare that to the width of the form, and move our controls accordingly.
Dim Ctrl As Control
Dim ClosestLeft As Integer
Dim FurthestRight As Integer
Dim FurthestRightWidth As Integer
Dim GrandTotalWidth As Integer
Dim AmountToMove As Integer
Dim TypicalPosition As Integer


'Finds the furthest left position of all of our controls on the form.
For Each Ctrl In Me
    If ClosestLeft > Ctrl.Left Or ClosestLeft = 0 Then
        ClosestLeft = Ctrl.Left
    End If

'Finds the furthest right control. Also takes the width of that furthest right control (necessary for the calculation)
    If FurthestRight < Ctrl.Left Or FurthestRight = 0 Then
        FurthestRight = Ctrl.Left
        FurthestRightWidth = Ctrl.Width
    End If
Next

'Now we find the grand total width of all of our controls. Furthest Right - Furthest Left + FurthestRightWidth
GrandTotalWidth = FurthestRight - ClosestLeft + FurthestRightWidth

'Finds the typical position of where the left side of the group of controls should sit on the form.
TypicalPosition = (Me.InsideWidth / 2) - (GrandTotalWidth / 2)

'Figures out the amount we'd have to move the group of controls to get them to sit in their typical position.
AmountToMove = TypicalPosition - ClosestLeft

For Each Ctrl In Me
    If Not ClosestLeft + AmountToMove <= 0 Then
        Ctrl.Left = Ctrl.Left + AmountToMove
    End If
Next


End Sub

现在,当您 运行 弹出式表单时,所有控件都应作为一个组集中在表单中。

Thebaby 提交的答案是一个优雅的解决方案 - 我已经尝试了几个。我是 运行 在 Windows 10.

访问 16

我建议将 Sub CenterControls() 作为 Public 函数放入模块中,并从您使用的每个表单的 Form_Resize() 和 Form_Current() 中调用它它。

作为一个 Public 函数,您需要用 screen.activeform 和相关的 属性.[= 替换所有对 Me 的引用,它只能在表单内调用10=]

例如: 对于我体内的每一个 Ctrl 对于 screen.activeform.controls

中的每个 Ctrl

TypicalPosition = (Me.InsideWidth / 2) - (GrandTotalWidth / 2) 需要更新为:TypicalPosition = (screen.activeform.InsideWidth / 2) - (GrandTotalWidth / 2)

扩展 Thebaby 的优雅方法、donohealy 的添加和添加 Ben McIntyre 的标记,我能够想出这个模块功能。

主要区别:

  1. 修复了一个不考虑宽对象的小数学问题
  2. 现在控制 Y 轴
  3. 标记允许对移动的内容进行精细控制(原来的选项卡控件已损坏)
  4. 修复了用户评论 donohealy 的 post 提到
  5. 的问题

缺点:

  1. 还是不够流畅
  2. 列表框仍然很奇怪
  
    Public Function CenterControls(obj As Form, Centertag As String, Middletag As String)

    'Find the control that has the farthest left position, and the one with the farthest right position.
    'That will give us the total distance of our buttons. We will then have to compare that to the width of the form, and move our controls accordingly.
    Dim Ctrl As Control
    Dim ClosestLeft As Integer
    Dim FurthestRight As Integer
    Dim GrandTotalWidth As Integer
    Dim AmountToMoveLR As Integer
    Dim TypicalPositionLR As Integer

    Dim ClosestTop As Integer
    Dim FurthestDown As Integer
    Dim GrandTotalHeight As Integer
    Dim AmountToMoveTB As Integer
    Dim TypicalPositionTB As Integer

    Dim StopLR As Boolean
    Dim StopTB As Boolean


    'Finds the furthest left position of all of our controls on the form.
    For Each Ctrl In obj
        If (Ctrl.Properties.Item("tag") = Centertag) Then
            If ClosestLeft > Ctrl.Left Or ClosestLeft = 0 Then
                ClosestLeft = Ctrl.Left
            End If
    
            'Finds the furthest right control. Also takes the width of that furthest right control (necessary for the calculation)
            If FurthestRight  Ctrl.Top Or ClosestTop = 0 Then
                ClosestTop = Ctrl.Top
            End If
    
            'Finds the furthest right control. Also takes the width of that furthest right control (necessary for the calculation)
            If FurthestDown = obj.InsideWidth Then StopLR = True
    If (ClosestLeft + AmountToMoveLR) = obj.InsideHeight) Then StopTB = True
    If (ClosestTop + AmountToMoveTB