使用名称检查用户表单中是否存在文本框

问题描述 投票:0回答:5

我创建了一个 Ms-Access 用户表单,其中有许多文本框。这些盒子被命名为:Box1、Box2、Box3 ...

我需要循环遍历所有框,但我不知道哪个是最后一个。为了避免循环遍历所有用户窗体控件,我想到了以下内容:

For i =1 To 20

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

此错误发生在 Box6,这是第一个未找到的盒子。有没有办法捕获这个错误并退出循环?

我可以使用

On Error
,但我宁愿用代码捕获这个特定的实例。

vba ms-access userform
5个回答
5
投票

A

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

首先,即使是可创建的集合对象也缺少

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

如果您真的不喜欢“请求宽恕而不是许可”选项,您可以提取文本框的整个有序集合(和/或在具有类似逻辑的另一个循环中按名称检查是否存在)。

Public Function PullBoxes() As Collection
    Dim Control As MSForms.Control

    Set PullBoxes = New Collection

    For Each Control In Me.Controls
        If TypeOf Control Is MSForms.TextBox And _
                Left(Control.Name, 3) = "Box" Then
                Call PullBoxes.Add(Control)
        End If
    Next
End Function

由于小部件的名称是唯一的 - 您可以从该函数返回一个

Dictionary
,其中包含 (Control.Name, Control) 对,并且能够通过名称正确检查小部件的存在性,而无需抑制错误。 如果这对您来说是新信息,那么有一个很好的指南
Dictionary

无论如何,无论您选择什么对象,如果用户(或代码)无法创建更多这些文本框 - 您可以将上面的

Function
转换为
Static Property Get
或仅转换为带有
Property Get
集合的
Static
内部,因此您只需迭代所有控件一次(例如,在
UserForm_Initialize
事件上)!

Public Property Get Boxes() As Collection
    Static PreservedBoxes As Collection

    'There's no loop, but call to PullBoxes to reduce duplicate code in answer
    If PreservedBoxes Is Nothing Then _
            Set PreservedBoxes = PullBoxes

    Set Boxes = PreservedBoxes
End Property

毕竟,最后创建的名为

TextBox
Box*
将会是:

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

我想现在事情对你来说更加清楚了!干杯!

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


2
投票

长话短说——你不能用 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

取自这里:http://www.tek-tips.com/viewthread.cfm?qid=1029435

要查看整个代码的工作情况,请像这样检查:

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

0
投票

我建议按照下面的另一个程序测试是否存在:-

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。


0
投票

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

如果您想限制循环,您可以仅在控件所在的部分循环,例如细节。您可以使用

ControlType
属性将控件限制为 TextBox。

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

我相信循环会比通过辅助函数和

On Error Resume Next
检查控件名称是否存在更快。

但这只是个人意见。


0
投票

我通过搜索“ms word 365 vba 如何确定文档中是否存在特定文本框”找到了这篇文章。

就我而言,我正在 MS Word 中创建绘图。我有几个组合在一起的“绘图对象”以及包含不同文本(ID 号)的相似组的多个副本。

因此,为了避免每次生成新绘图时都重新发明轮子,我打开现有绘图,使用新名称另存为,然后使用 VBA 将绘图对象重新定位在文档一侧更改绘图并将 ID 号放置在新文档上的正确位置。

根据我创建的绘图类型,某些绘图将具有特定的“绘图对象”,而其他绘图则不会。所以我使用以下方法来确定该特定对象是否存在......

Private Sub sort_Nums()
  Dim grp As Shape, shp As Object
  Dim id As String    '<-- object id - could be a # &/or a letter
  Dim flg_It_Exists As Boolean

  Set doc = Application.ActiveDocument
  flg_It_Exists = False

  For Each grp In doc.Shapes
    If grp.Type = 6 Then    '<-- if shape is a group then
      For Each shp In grp.GroupItems
        If shp.Type = 17 Then    '<-- if group contains a textbox then
          'pop var "id" to get ID, trim & strip all vbCR/vbLR/vbCRLF
          If IsNumeric(id) Then
            'manage stuff for # ID
          ElseIf [id=string ID] Then
            'manage stuff for string ID
          ElseIf [id=specific ID] Then
            'manage stuff for specific ID
            flg_It_Exists = True
          End If
        End If
      Next shp
    End If
  Next grp

  'reposition specific object
  If flg_It_Exists Then
    'move specific object to its default starting position
  End If

  'code to manage other objects here
  
  Set doc = Nothing
End Sub

我意识到OP正在询问MS Access中的用户表单,但底层逻辑可能仍然适用。

© www.soinside.com 2019 - 2024. All rights reserved.