MSAccess VBA Control.Parent 违规行为
MSAccess VBA Control.Parent Irregularities
我发现 Control.Parent
可能指的是 Form
或者它也可能是 Page
如果它在 TabControl
中。过去,我只是抓住了父级,它是一个表单,即使对于选项卡上的控件也是如此。更让我困惑的是,subform
控件似乎有 Form
作为 .Parent
,但没有其他控件有(请注意,这可能并不总是如@FunThomas 所示);但在我的 Access 版本中就是这种情况。
MSAccess's Control.Parent Documentation while being fairly terse, just says "Returns the parent object for the specified object." Some research has stated the control parent is the form, even for controls on tabs, so I'm more confused. Even Microsoft's page on referring to controls says either are valid,这让我想知道这在过去是否有效,或者我只是在想象。
给定一个名为 TopForm 的 Form
和一个名为 TabCtl1 的 TabControl
,一个 Page
名为TabPage1,各种控件(SubForm
、TextBox
等)都在一个窗体的Tab Page上,下面好像是这样。
,并被要求充实我在实施解决方案时发现的边缘案例。
注意:本例中的所有控件都在一个“页面”上(由于某些原因,子表单在另一个标签页上):
Control Type
Control.Parent
Returns
Parent Type
Expected Parent
TabCtl1
TopForm
Form
TopForm
TabPage1
TabCtl1
TabControl
TabCtl1
TabPage2
TabCtl1
TabControl
TabCtl1
SubFormCtl
TopForm
Form
TabPage2
ListBoxCtl
TabPage1
Tab Page
Tab Page 1
TextBoxCtl
TabPage1
Tab Page
Tab Page 1
现在,问题是:我做错了什么?在获得控件的父窗体之前,我是否需要遍历所有父窗体?
控件在其他控件中“实时”。您可以通过 属性 Parent
.
获取他们所在的控件
如果一个控件“内部”有一个或多个控件,您可以通过 属性 Controls
获取列表,但请注意并非所有控件类型都可以有子控件,例如标签不能有子控件并且没有 Controls
-属性.
这个parent-child关系可以级联。你可以有一个带页面的选项卡控件,一个页面可以包含一组选项按钮。你会得到类似
的东西
Form
TabControl
Page 1
Frame 2
Label 3
Check 4
您确定您的子表单位于页面控件上吗?如果是,它应该将 Page 控件作为父级,而不是 Main 窗体 - 至少在我测试代码的示例中就是这种情况。
链接到控件的标签,例如输入字段旁边的标签将该控件作为父控件。作为一个经验法则:如果您移动一个控件并且其他控件也随之移动,那么这些控件是子控件而您移动的控件是父控件。
以下函数将 return top-most 父级,应该是表单。
Function getForm(ctrl As Variant) As Variant
Dim Parent As Variant
On Error Resume Next
Set parent = ctrl.parent
On Error GoTo 0
If IsEmpty(parent) Then
Set getForm = ctrl
Else
Set getForm = getForm(parent)
End If
End Function
经过大量的测试和摸索,我发现解决方案比预期的要简单得多。我使用了@Nathan_Sav's 和@FunThomas's 并最终将它们融合在一起以确保我可以做我需要的事情。
我按照@AlbertD.Kallal的建议使用父表单(这样我就可以 select 父 Form
和子 Control
并在需要时恢复操作,或者只是记录更改)。我想要父表单,因为简单地使用 FrmInUse.ControlToActOn.WhateverINeedToDo
而不是沿着树向下走是最简单和最一致的。我最近发布的另一个答案中使用了这种方法:。这个问题试图弄清楚为什么 .Parent
没有始终如一地返回。
我想,可以将所有控件激活到我想要的那个(这将确保选项卡打开到所需位置),但是,用户表示没有按照他们的预期进行操作并且也会触发事件(尽管 Microsoft's TabControl.Change Documentation 说 VBA 不会触发事件,但我在实践中发现在我的 Access 版本中显然不是这样)。
以循环(Form.SfrmControl.Sfrm.CtrlIWant
或 Form.CtrlIWant
)一致解析的方式获取 Control
的 Parent
,并假定 Control
或者 Form
有一个父对象(在其他地方检查过),这就是我要找的东西。
If TypeOf ControlTarget Is Form Then
Set ParentForm = ControlTarget.Parent
Else
Set ParentForm = ControlTarget.Properties.Parent.Form
End If
代码然后像这样使用:(伪代码,同时我们完善它并测试边缘情况,我计划稍后发布完全构建的 class 和组件)。
Public Sub GetAddress(ByRef FormOrControlTarget As Object) As String
Dim ParentForm As Access.Form
If TypeOf FormOrControlTarget Is Form Then
Set ParentForm = FormOrControlTarget.Parent
Else
Set ParentForm = FormOrControlTarget.Properties.Parent.Form
End If
If ParentForm Is Nothing Then
GetAddress = FormOrControlTarget.Name & FormOrControlTarget.Hwnd
ElseIf FormOrControlTarget Is Form Then
' Note: the below line won't work as-is, you'll need to search the parent form
' for it; I'll update this and the relevant code when it's ready to go.
GetAddress = ParentForm.Name & ParentForm.SfrmControl.Name & FormOrControlTarget.Name & FormOrControlTarget.Hwnd
Else
GetAddress = ParentForm.Name & ParentForm.Hwnd & FormOrControlTarget.Name
End if
End Sub
我发现 Control.Parent
可能指的是 Form
或者它也可能是 Page
如果它在 TabControl
中。过去,我只是抓住了父级,它是一个表单,即使对于选项卡上的控件也是如此。更让我困惑的是,subform
控件似乎有 Form
作为 .Parent
,但没有其他控件有(请注意,这可能并不总是如@FunThomas 所示);但在我的 Access 版本中就是这种情况。
MSAccess's Control.Parent Documentation while being fairly terse, just says "Returns the parent object for the specified object." Some research has stated the control parent is the form, even for controls on tabs, so I'm more confused. Even Microsoft's page on referring to controls says either are valid,这让我想知道这在过去是否有效,或者我只是在想象。
给定一个名为 TopForm 的 Form
和一个名为 TabCtl1 的 TabControl
,一个 Page
名为TabPage1,各种控件(SubForm
、TextBox
等)都在一个窗体的Tab Page上,下面好像是这样。
注意:本例中的所有控件都在一个“页面”上(由于某些原因,子表单在另一个标签页上):
Control Type | Control.Parent Returns |
Parent Type | Expected Parent |
---|---|---|---|
TabCtl1 | TopForm | Form | TopForm |
TabPage1 | TabCtl1 | TabControl | TabCtl1 |
TabPage2 | TabCtl1 | TabControl | TabCtl1 |
SubFormCtl | TopForm | Form | TabPage2 |
ListBoxCtl | TabPage1 | Tab Page | Tab Page 1 |
TextBoxCtl | TabPage1 | Tab Page | Tab Page 1 |
现在,问题是:我做错了什么?在获得控件的父窗体之前,我是否需要遍历所有父窗体?
控件在其他控件中“实时”。您可以通过 属性 Parent
.
获取他们所在的控件
如果一个控件“内部”有一个或多个控件,您可以通过 属性 Controls
获取列表,但请注意并非所有控件类型都可以有子控件,例如标签不能有子控件并且没有 Controls
-属性.
这个parent-child关系可以级联。你可以有一个带页面的选项卡控件,一个页面可以包含一组选项按钮。你会得到类似
的东西Form
TabControl
Page 1
Frame 2
Label 3
Check 4
您确定您的子表单位于页面控件上吗?如果是,它应该将 Page 控件作为父级,而不是 Main 窗体 - 至少在我测试代码的示例中就是这种情况。
链接到控件的标签,例如输入字段旁边的标签将该控件作为父控件。作为一个经验法则:如果您移动一个控件并且其他控件也随之移动,那么这些控件是子控件而您移动的控件是父控件。
以下函数将 return top-most 父级,应该是表单。
Function getForm(ctrl As Variant) As Variant
Dim Parent As Variant
On Error Resume Next
Set parent = ctrl.parent
On Error GoTo 0
If IsEmpty(parent) Then
Set getForm = ctrl
Else
Set getForm = getForm(parent)
End If
End Function
经过大量的测试和摸索,我发现解决方案比预期的要简单得多。我使用了@Nathan_Sav's 和@FunThomas's 并最终将它们融合在一起以确保我可以做我需要的事情。
我按照@AlbertD.Kallal的建议使用父表单(这样我就可以 select 父 Form
和子 Control
并在需要时恢复操作,或者只是记录更改)。我想要父表单,因为简单地使用 FrmInUse.ControlToActOn.WhateverINeedToDo
而不是沿着树向下走是最简单和最一致的。我最近发布的另一个答案中使用了这种方法:.Parent
没有始终如一地返回。
我想,可以将所有控件激活到我想要的那个(这将确保选项卡打开到所需位置),但是,用户表示没有按照他们的预期进行操作并且也会触发事件(尽管 Microsoft's TabControl.Change Documentation 说 VBA 不会触发事件,但我在实践中发现在我的 Access 版本中显然不是这样)。
以循环(Form.SfrmControl.Sfrm.CtrlIWant
或 Form.CtrlIWant
)一致解析的方式获取 Control
的 Parent
,并假定 Control
或者 Form
有一个父对象(在其他地方检查过),这就是我要找的东西。
If TypeOf ControlTarget Is Form Then
Set ParentForm = ControlTarget.Parent
Else
Set ParentForm = ControlTarget.Properties.Parent.Form
End If
代码然后像这样使用:(伪代码,同时我们完善它并测试边缘情况,我计划稍后发布完全构建的 class 和组件)。
Public Sub GetAddress(ByRef FormOrControlTarget As Object) As String
Dim ParentForm As Access.Form
If TypeOf FormOrControlTarget Is Form Then
Set ParentForm = FormOrControlTarget.Parent
Else
Set ParentForm = FormOrControlTarget.Properties.Parent.Form
End If
If ParentForm Is Nothing Then
GetAddress = FormOrControlTarget.Name & FormOrControlTarget.Hwnd
ElseIf FormOrControlTarget Is Form Then
' Note: the below line won't work as-is, you'll need to search the parent form
' for it; I'll update this and the relevant code when it's ready to go.
GetAddress = ParentForm.Name & ParentForm.SfrmControl.Name & FormOrControlTarget.Name & FormOrControlTarget.Hwnd
Else
GetAddress = ParentForm.Name & ParentForm.Hwnd & FormOrControlTarget.Name
End if
End Sub