2017-05-30 61 views
2

我正在使用Ms-Access,並創建了一個包含多個文本框的用戶窗體。這些框被命名爲:Box1,Box2,Box3 ...檢查文本框是否存在vba(使用名稱)

我需要遍歷所有框,但我不知道哪一個是最後一個。爲了避免循環遍歷所有用戶表單控件,我想嘗試以下操作:

For i =1 To 20 

if Me.Conrtols("Box" & i).value = MyCondition Then 

'do stuff 

Next i 

在Box6(這是第一個未找到的框)中發生此錯誤。有沒有辦法捕獲這個錯誤並在發生時退出循環。

我知道我可以使用On Error但我寧願用代碼來捕獲這個特定的實例。

感謝, 喬治

+2

我很驚訝任何迭代在'Conrtols'對象上工作:P –

+1

@MacroMan - 它可能是用戶定義的:} – Vityata

+2

這不是一種在Access中使用表單的非常糟糕的方式嗎?您正在尋找最後一個控件時,建議您在運行時將文本框添加到表單中,因爲您需要在設計模式下打開表單,所以我一直覺得這是一個糟糕的主意(在Access中)在添加控件之前,添加代碼,以便您可以使用按鈕(而不是鉤住控件的類) - 這個問題不是指出表單設計會更好,還是可能有更好的解決方案? –

回答

0

長話短說 - 你不能做你想要什麼樣的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

單獨的功能可能是一個答案。去'Else Exit For'。它似乎是或者循環,雖然所有的控件只有當初始化表單並獲得循環的最終值 – George

+0

@George - 代碼的想法是顯示'fnBlnExists'如何工作。因此,我已經把'debug.print'。 – Vityata

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 if該框確實存在。

2

A Controls集合是控件(顯然)的簡化集合,並且與控件的放置順序共享相同的順序。首先,即使是可創建的集合對象也缺少方法,例如ExistsContains,因此您需要一個具有錯誤處理功能來從集合中檢查/拉取小部件。

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 

由於部件的名稱是唯一的 - 你可以從函數(Control.Name,控制)對內部,能夠通過名稱來檢查控件的所有腦幹適當W/O錯誤抑制返回DictionaryThere's一個很好的指南Dictionary如果它是一個新的信息給你。

反正不管你選擇什麼樣的對象,如果用戶(或代碼)是無法創造更多的thoose文本框的 - 你可以把這個Function上面的Static Property Get或只是一個Property GetStatic集裏面,這樣你迭代超過所有控件只有一次(例如在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 

我想,現在的東西更清晰給你!乾杯!

注:所有的代碼都是你的窗體的一堆方法/屬性,因此所有的東西都應該放在窗體模塊的內部。

+0

僅在初始化表單時循環遍歷所有控件是個不錯的主意。你添加了很多有益於學習的信息。但爲什麼不(爲此目的)通過添加MyBoxes = MyBoxes + 1而不是'Call PullBoxes.Add(Control)'來縮寫所有內容? MyBoxes可以是表單上的一個公共變量或一個隱藏的標籤。 – George

+0

@George,抱歉,什麼是MyBoxes變量?代表計數器的'Long'變量?如果是,那麼你可以檢查一個Collection/Dictionary的Count屬性。如果你想做一個公共集合而不是屬性 - 取決於你,那麼與這兩者的行爲沒有區別(但取決於你將放置你的公共變量的位置)。如果它是某種迭代器/當前索引 - 那麼請詳細說明你需要什麼原因? – CommonSense

+0

我在問是否更好的方法是將'Public Function PullBoxes()'作爲集合'替換爲'Public Function MyBoxes()as integer'。初始化表單並計算我擁有的Box數時,MyBoxes會運行。將所有內容縮短到'for.controls'循環中的每個控件。 「Existswidget」,「getboxes」和「lastcreatedbox」將不再需要。 – George

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

Geia sou Kosta :)。感謝你的回答。這確實有效,但它貫穿所有控制。我還需要一個額外的條件,以便'如果ctl.controltype = acTextBox和LEFT(ctl.name,3)=「Box」Then'。這就是爲什麼我只想循環控制名爲Box1,Box2等等 – George

+0

Geia sou Giwrgo :)。我不能幫助問你爲什麼只需要在名爲「Box」的文本框中循環。表單有多少個控件? –

+0

沒有那麼多,這是必須的。我目前正在循環所有控件,並且沒有延遲記錄。但我是編程新手,我試圖讓它成爲一種高效工作的習慣。因此,要回答你的問題a)我想知道它是否可行並學會如何去做,b)我想使它成爲一種習慣,至少想到更有效的方法,這樣我至少可以評論我的代碼並修改如果需要的話,稍後階段。請記住,通過詢問,我還得到了更好的形式設計的有用評論,並將其作爲替代方式作爲回答 – George

相關問題