VBA迭代主窗体上的控件,同时忽略子窗体

Posted

技术标签:

【中文标题】VBA迭代主窗体上的控件,同时忽略子窗体【英文标题】:VBA Iterate over controls on main form while ignoring subform 【发布时间】:2015-06-02 14:48:32 【问题描述】:

我有一个按钮,用于清除(搜索)表单上的所有活动控件。但是,每个搜索的输出都显示在一个子窗体中,并且似乎是作为文本框实现的。 (虽然它显示为电子表格,但子表单的设计视图显示文本框。)

因此,当我将表单上所有 acTextBox 控件的 Value 设置为 "" 时,它也会清除子表单上的某些内容,并且所有进一步的搜索都会在所有字段中返回 #Name,直到表单重新打开。

此外,在发生此错误时,单击子表单的 Form 对象会生成一条消息警告 Object invalid or no longer set. 尝试编辑关联方法通常会导致表单在设计视图中打开并获得焦点,这可能会或可能会不显着。 (如果设计视图尚未打开,则只要在方法中按下一个键就会发生这种情况。)

问题似乎在以下块中:

Dim ctl As Control
For Each ctl In Me.Controls
        If (ctl.ControlType = acTextBox) Then
            If Len(ctl.Properties("ControlSource")) = 0 Then
                ctl.Value = "" '***
            End If
        ElseIf ctl.ControlType = acCheckBox Then
            ctl.Value = False
        ElseIf ctl.ControlType = acComboBox Then
            ctl.Value = ""
        End If
Next ctl

'*** 后面的赋值是我缩小问题范围的地方,因为注释掉该行可以防止问题发生——但是将文本框的值设置为“”是我我正在尝试做,我不能摆脱它。

ControlSource 长度比较试图从下一行中排除子表单项,因为它们都是绑定的,而主表单项不是。它是嵌套的(与 If (... And ...) 相反),因为 VBA 没有惰性 Or。

需要做些什么来迭代所有主窗体控件而不影响子窗体控件?

编辑:子表单/查询的说明。

子表单使用以下语句从查询中提取数据:

SELECT DW_Query.Map_Number, DW_Query.Map_Name, DW_Query.Map_Type, DW_Query.Town, DW_Query.Address, DW_Query.Street, DW_Query.Block, DW_Query.Lot, DW_Query.group, DW_Query.Folder, DW_Query.Latitude, DW_Query.Longitude FROM DW_Query;

似乎 Town 字段可能会以某种方式被删除,因为有时会有一个 RTE 2465 的实例,can't find the field 'Town' referred to in your expression. 但是,这发生在主窗体的 Form_Open 子中,在以下行中:

Me.DW_Query_subform.Form.RecordSource = "SELECT DW_Query.Map_Number, DW_Query.Map_Name, DW_Query.Map_Type, DW_Query.Town," & _
    "DW_Query.Address, DW_Query.Street, DW_Query.Block, DW_Query.Lot, DW_Query.group, DW_Query.Folder, DW_Query.Latitude, DW_Query.Longitude " & _
    "FROM DW_Query;" 'Set subform to use address query. (Faster)

【问题讨论】:

记住子窗体是主窗体上的控件。但是它不应该受到影响,因为您正在测试控制类型。你调试过代码吗? 子表单是否设置了子/主字段? 老实说,我并不完全确定您所说的“调试代码”是什么意思;我还不熟悉 Access 中的调试工具。我的编译没有错误,但到目前为止还没有设置断点或对“立即”窗口进行任何操作(因为我不知道该放什么会有帮助)。 基本上,您只需在For Each ctl In Me.Controls 附近的某处放置一个断点,只需单击该行的左侧即可设置断点。代码将停在那里,然后您可以使用 F8“遍历”代码(至少对于 2010 年)。 【参考方案1】:

您需要设置为 Null,因为文本框可能不接受空字符串:

Dim ctl As Control
For Each ctl In Me.Controls
        If (ctl.ControlType = acTextBox) Then
            If Len(ctl.Properties("ControlSource")) = 0 Then
                ctl.Value = Null
            End If
        ElseIf ctl.ControlType = acCheckBox Then
            ctl.Value = False
        ElseIf ctl.ControlType = acComboBox Then
            ctl.Value = Null
        End If
Next ctl

【讨论】:

这是 2007 年的问题,还是有一些文档可以支持?我想看看我的数据库,我有将近 100 个地方,我有 ctr.Value = "" 和零个说 ctr.Value = Null 虽然这确实解决了#Name 结果的问题,(不知何故——我必须同意 Newd 的观点,我从未听说过这个问题,其他此类任务也可以正常工作。)相反,它会导致子表单显示它从中提取的数据库的同一子集,而不考虑来自主表单的输入。 这似乎可行,实际上。我根据其他地方的建议进行了其他更改,这似乎使古斯塔夫的建议无效;在还原它们并应用此方法后,原始问题已解决而没有造成任何问题,因此我将其标记为答案。【参考方案2】:

您可以缩小迭代范围,例如仅清除“详细信息”部分中的控件

Dim ctl As Control
For Each ctl In Me.Detail.Controls
        If (ctl.ControlType = acTextBox) Then
            If Len(ctl.Properties("ControlSource")) = 0 Then
                ctl.Value = vbnullString
            End If
        ElseIf ctl.ControlType = acCheckBox Then
            ctl.Value = False
        ElseIf ctl.ControlType = acComboBox Then
            ctl.Value = Null
        End If
Next ctl

【讨论】:

不幸的是,这似乎不起作用。我已将子表单移至页脚部分并遍历Me.Detail.Controls,但我仍然遇到了我在对 Gustav 的回答的第一条评论中描述的问题。

以上是关于VBA迭代主窗体上的控件,同时忽略子窗体的主要内容,如果未能解决你的问题,请参考以下文章

C# Winform主窗体和子窗体之间如何相互操作对方的控件

单击父窗体时不会触发访问 VBA 子窗体事件

Qt:子窗口中如何获取主窗体ui中的控件

隐藏/取消隐藏基于控件标签的主窗体上的控件,在连续子窗体中使用当前事件

delphi 子窗体传值问题子窗体调用

WPF中窗体打开的位置怎么控制?