Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/vba/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
检查文本框是否存在vba(使用名称)_Vba - Fatal编程技术网

检查文本框是否存在vba(使用名称)

检查文本框是否存在vba(使用名称),vba,Vba,我使用Ms Access创建了一个userform,上面有许多文本框。这些盒子的名字是:盒子1,盒子2,盒子3 我需要遍历所有的框,但我不知道哪一个是最后一个。为了避免在所有userform控件中循环,我考虑尝试以下方法: For i =1 To 20 If Me.Controls("Box" & i).value = MyCondition Then 'do stuff End If Next i 此错误出现在第6框,这是未找到的第一个框。是否有方法捕

我使用Ms Access创建了一个userform,上面有许多文本框。这些盒子的名字是:盒子1,盒子2,盒子3

我需要遍历所有的框,但我不知道哪一个是最后一个。为了避免在所有userform控件中循环,我考虑尝试以下方法:

For i =1 To 20

If Me.Controls("Box" & i).value = MyCondition Then
    'do stuff
End If

Next i
此错误出现在第6框,这是未找到的第一个框。是否有方法捕获此错误并在发生时退出循环

我知道我可以在出错时使用
,但我宁愿用代码来捕获这个特定实例

谢谢,
乔治(George)

长话短说——你不能用VBA做你想做的事。 然而,有一个很好的方法可以解决这个问题——制作一个布尔公式,使用
On Error
检查对象是否存在。因此,您的代码不会被它破坏

Function ControlExists(ControlName As String, FormCheck As Form) As Boolean
   Dim strTest As String
   On Error Resume Next
   strTest = FormCheck(ControlName).Name
   ControlExists = (Err.Number = 0)
End Function
摘自这里:

要查看整个代码是否正常工作,请按如下方式进行检查:

Option Explicit

Sub TestMe()

    Dim i       As Long

    For i = 1 To 20
        If fnBlnExists("Label" & i, UserForm1) Then
            Debug.Print UserForm1.Controls(CStr("Label" & i)).Name & " EXISTS"
        Else
            Debug.Print "Does Not exist!"
        End If
    Next i

End Sub

Public Function fnBlnExists(ControlName As String, ByRef FormCheck As UserForm) As Boolean

    Dim strTest As String
    On Error Resume Next
    strTest = FormCheck(ControlName).Name
    fnBlnExists = (Err.Number = 0)

End Function

我建议根据以下要求,在另一个程序中测试是否存在:-

Private Sub Command1_Click()
Dim i As Long

i = 1
Do Until Not BoxExists(i)
    If Me.Conrtols("Box" & i).Value = MyCondition Then
        'Do stuff
    End If
    i = i + 1
Next
End Sub

Private Function BoxExists(ByVal LngID As Long) As Boolean
Dim Ctrl As Control

On Error GoTo ErrorHandle

Set Ctrl = Me.Controls("BoX" & LngID)
Set Ctrl = Nothing

BoxExists = True

Exit Function
ErrorHandle:
Err.Clear
End Function
在上面的示例中,
BoxExists
仅当框确实存在时才返回true。

集合是控件的简化集合(显然),并且与控件的放置顺序共享相同的顺序

首先,即使是可创建的集合对象也缺少方法,例如
Exists
Contains
,因此您需要一个带有错误处理的函数来检查/从集合中提取小部件

Public Function ExistsWidget(ByVal Name As String) As Boolean
    On Error Resume Next
        ExistsWidget = Not Me.Controls(Name) Is Nothing
    On Error GoTo 0
End Function
如果你真的不喜欢“请求原谅而不是许可”选项,你可以拉整个文本框的有序集合(和/或在另一个具有类似逻辑的循环中按名称检查存在)

由于小部件的名称是唯一的-您可以从该函数返回一个
字典
,其中包含(Control.Name,Control)对,并且能够正确地按名称检查小部件的存在,而无需进行错误抑制。 如果这是给你的新信息,这是一本很好的
词典指南

无论如何,无论您选择什么对象,如果用户(或代码)无法创建更多这些文本框,您可以将上面的
函数
转换为
静态属性Get
或仅转换为
属性Get
,其中包含
静态
集合,因此您只需在所有控件上迭代一次(例如,在
UserForm\u初始化
事件上)

毕竟,最后创建的名为
Box*
TextBox
将是:

Public Function LastCreatedBox() As MSForms.TextBox
    Dim Boxes As Collection

    Set Boxes = PullBoxes

    With Boxes
        If .Count <> 0 Then _
                Set LastCreatedBox = Boxes(.Count)
    End With
End Function
公共函数LastCreatedBox()作为MSForms.TextBox
暗箱收藏
集合框=拉线框
用盒子
如果是,那么数到0_
设置LastCreatedBox=box(.Count)
以
端函数
我想现在事情对你来说更清楚了!干杯


注意:所有代码都是表单的一组方法/属性,因此所有内容都应该放在表单模块中。

您在这里采取了错误的方法

如果要限制循环,则只能在控件所在的部分(例如详细信息)中循环。可以使用
ControlType
属性将控件限制为文本框

Dim ctl As Control
For Each ctl In Me.Detail.Controls
    If ctl.ControlType = acTextBox Then
        If ctl.Value = MyCondition Then
            'do stuff
        End If
    End If
Next ctl
我相信循环会比通过helper函数和
On Error Resume Next
检查控件名称是否存在更快


但这只是我个人的观点。

我对
Conrtols
对象上的任何迭代工作感到惊讶:P@MacroMan-它可能是用户定义的:}这不是在Access中使用表单的一种非常糟糕的方式吗?如果您正在查找最后一个控件,则表明您在运行时向表单添加了文本框,而我一直在使用它n这是一个坏主意(在Access中),因为在添加控件之前需要在设计模式下打开窗体,请添加代码以便可以使用按钮(而不是连接到控件中的类)-这个问题不是指出表单设计可能更好,或者可能有更好的解决方案吗?@DarrenBartrup Cook-我需要具有类似初始设计的may表单从同一位置提取数据。但是在如何分析这些数据方面有很大的不同。每个框将采用用户定义的标识符。因此,这是将可以在许多表单上使用。不同表单中的框数可以从5到15不等。所以我想给它们取一个相同的名称(在实际实现中不会是框)。我想我可以在所有表单上都有20个框,并隐藏不活动的框,但我宁愿不这样做。
Me。控件
最终也将不得不更改,但在当时是无关紧要的,因为如果表单设计足够相似,我可能会使用一个表单和20个框,并编写所有分析代码来处理该表单某种标识符告诉它要执行哪种分析。因此,大多数代码实际上不会位于表单中,而是位于从表单调用的普通模块中。或者是交换机样式的表单-在连续表单上有一个按钮,连接到一个包含按钮文本和参数的表。Geia sou Kosta:)。谢谢你的回答。这确实有效,但它会在所有控件中循环。我还需要一个附加条件,以便
如果ctl.controltype=acTextBox且LEFT(ctl.name,3)=“Box”,则
。这就是为什么我只想通过名为Box1、Box2等的控件进行循环:)。我不禁要问,为什么只需要在名为“Box”的文本框上循环。表单有多少个控件?没有那么多控件使其成为必须的。我目前正在遍历所有控件,没有发现任何延迟。但我对编程还不熟悉,我正在努力使高效工作成为一种习惯。因此,为了回答您的问题a)我想知道这是否可能,并学习如何做;b)我想养成一种习惯,至少思考更有效的方法,这样我至少可以评论我的代码,并在以后需要时进行修改。请记住,通过提问,我也得到了关于更好的表单设计的有用意见,并回答了关于集合的问题,作为一种替代方法。分离功能可能是一个答案。去吧
Public Function LastCreatedBox() As MSForms.TextBox
    Dim Boxes As Collection

    Set Boxes = PullBoxes

    With Boxes
        If .Count <> 0 Then _
                Set LastCreatedBox = Boxes(.Count)
    End With
End Function
Dim ctl As Control
For Each ctl In Me.Detail.Controls
    If ctl.ControlType = acTextBox Then
        If ctl.Value = MyCondition Then
            'do stuff
        End If
    End If
Next ctl