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,这让我想知道这在过去是否有效,或者我只是在想象。

给定一个名为 TopFormForm 和一个名为 TabCtl1TabControl,一个 Page名为TabPage1,各种控件(SubFormTextBox等)都在一个窗体的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.CtrlIWantForm.CtrlIWant)一致解析的方式获取 ControlParent,并假定 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