@Tim Lentine 的建议非常好,在我看来直接回答了你的问题。
但我可能永远不会编写对表单的整个控件集合进行操作的子程序。原因是这样做实际上效率很低。但它是否合适取决于您步行该系列的频率和时间。
如果您在表单的 OnLoad 事件中执行过一次(您不希望在 OnOpen 中执行此操作,因为此时不能保证控件的数据绑定属性完全初始化 - 您不过,仍然可以对格式属性进行操作——但在 OnLoad 事件触发时一切都准备就绪),这没什么大不了的,将该集合传递给外部子例程是合适的。
但是,如果您为每条记录遍历它(例如隐藏/显示控件,或在未绑定的按表单查询界面中初始化条件字段),那么您将通过使用一个或多个显着提高表单的性能与任何普通表单的控件集合相比,自定义集合要循环的项目数量要少得多。然后,您可以重写 Tim 的代码以使用自定义集合,或者就此而言,仍然可以使用上面的 Object 变量并将其传递给自定义集合(并且仍然能够将其传递给表单的控件集合)。
基本上,您所做的是在表单的 OnLoad 事件中初始化集合。我通常会编写一个私有子例程来执行此操作,以便在发生代码重置时重新初始化:
Private Sub SetupCollections()
If mcolCriteria.Count = 0 Then
Call PopulateCollections(Me, mcolCriteria, "Criteria")
End If
End Sub
Public Sub PopulateCollections(frm As Form, pcol As Collection, strTag As String)
Dim ctl As Control
For Each ctl In frm.Controls
If ctl.Tag = strTag Then
pcol.Add ctl, ctl.Name
End If
Next ctl
Set ctl = Nothing
End Sub
在这种情况下,我确定将哪些控件添加到集合中的方法是设置这些控件的 Tag 属性。您还可以执行以下操作:
Public Sub PopulateCollections(frm As Form, pcol As Collection, intControlType As AcControlType)
Dim ctl As Control
For Each ctl In frm.Controls
If ctl.ControlType = intControlType
pcol.Add ctl, ctl.Name
End If
Next ctl
Set ctl = Nothing
End Sub
要使用它,例如,您可以创建一个 Nullable 控件的集合,如下所示:
If mcolControlsNullable.Count = 0 Then
Call PopulateCollections(Me, mcolControlsNullable, acTextBox)
Call PopulateCollections(Me, mcolControlsNullable, acComboBox)
Call PopulateCollections(Me, mcolControlsNullable, acListBox)
End If
对于布尔控件:
If mcolControlsBoolean.Count = 0 Then
Call PopulateCollections(Me, mcolControlsBoolean, acCheckBox)
End If
对于具有默认值的选项组或其他控件:
If mcolControlsWithDefaults.Count = 0 Then
Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acTextBox)
Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acComboBox)
Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acListBox)
Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acCheckBox)
Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acOptionGroup)
End If
Public Sub PopulateCollectionsWithDefaults(frm As Form, pcol As Collection)
Dim ctl As Control
For Each ctl In frm.Controls
If Len(ctl.DefaultValue) > 0 Then
pcol.Add ctl, ctl.Name
End If
Next ctl
Set ctl = Nothing
End Sub
Private Sub SetControlValuesFromDefaults(pcol As Collection)
For Each ctl in pcol
ctl = ctl.DefaultValue
Next ctl
End Sub
对于其他系列:
Public Sub SetControlValues(pcol As Collection, varValue As Variant)
For Each ctl in pcol
ctl = varValue
Next ctl
End Sub
对于这组更复杂的集合,您需要这样的东西来初始填充它们:
Private Sub SetupCollections()
If mcolControlsNullable.Count = 0 Then
Call PopulateCollections(Me, mcolControlsNullable, acTextBox)
Call PopulateCollections(Me, mcolControlsNullable, acComboBox)
Call PopulateCollections(Me, mcolControlsNullable, acListBox)
End If
If mcolControlsBoolean.Count = 0 Then
Call PopulateCollections(Me, mcolControlsBoolean, acCheckBox)
End If
If mcolControlsWithDefaults.Count = 0 Then
Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acTextBox)
Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acComboBox)
Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acListBox)
Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acCheckBox)
Call PopulateCollectionsWithDefaults(Me, mcolControlsWithDefaults, acOptionGroup)
End If
End Sub
...那么你会想要一个 sub 来初始化控件值:
Private Sub InitializeControls()
Call SetControlValues(mcolControlsNullable, Null)
Call SetControlValues(mcolControlsBoolean, False)
Call SetControlValuesFromDefaults(mcolControlsWithDefaults)
End Sub
...这样您就可以在表单的 OnLoad 事件中设置所有内容:
Call SetupCollections()
Call InitializeControls()
当然,现在有一些不那么复杂的方法可以做到这一点。您可能希望初始化例程只遍历控件集合一次:
Private Sub SetupCollections()
Dim ctl As Control
For Each ctl in Me.Controls
If Len(ctl.DefaultValue) > 0 then
mcolControlsWithDefaults.Add ctl, ctl.Name
Else
Select Case ctl.ControlType
Case acTextBox, acComboBox, acListBox
mcolControlsNullable.Add ctl, ctl.Name
Case acCheckBox
mcolControlsBoolean.Add ctl, ctl.Name
End Select
End If
Next ctl
Set ctl = Nothing
End Sub
消除初始化例程的一种方法是使用自定义属性返回集合,使用内部静态变量,根据需要重新初始化。但是,这意味着要多次遍历控件集合,因此效率不高:
Private Property Get colControlsNullable() As Collection
Static colNullable As Collection
If colNullable.Count = 0 Then
Call PopulateCollections(Me, mcolControlsNullable, acTextBox)
Call PopulateCollections(Me, mcolControlsNullable, acComboBox)
Call PopulateCollections(Me, mcolControlsNullable, acListBox)
End If
Set colControlsNullable = colNullable
End Property
不幸的是,使用静态变量虽然很好地避免了模块级变量,但这意味着您的初始化例程效率较低,因为外部初始化例程无法利用这些静态变量通过控件来填充所有内容收藏。
所以,我不为这些集合使用自定义属性,尽管我希望可以。另一方面,如果我只有一个自定义控件集合,我会这样做。
不管怎样,我已经讨论了很久很久,而且卷积太多了,而且可能所有的空气代码都充满了错误......