如何动态地使控件在 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 的标记,我能够想出这个模块功能。
主要区别:
- 修复了一个不考虑宽对象的小数学问题
- 现在控制 Y 轴
- 标记允许对移动的内容进行精细控制(原来的选项卡控件已损坏)
- 修复了用户评论 donohealy 的 post 提到
的问题
缺点:
- 还是不够流畅
- 列表框仍然很奇怪
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
我在 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 的标记,我能够想出这个模块功能。
主要区别:
- 修复了一个不考虑宽对象的小数学问题
- 现在控制 Y 轴
- 标记允许对移动的内容进行精细控制(原来的选项卡控件已损坏)
- 修复了用户评论 donohealy 的 post 提到 的问题
缺点:
- 还是不够流畅
- 列表框仍然很奇怪
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