2011-09-08 77 views
-2

我的代碼是:VBA錯誤處理只適用於第一次通過

Sub zaa() 
'code to find another open file that has the defined name "data" 
' - useful where the name changes each month or week 

For Each wb In Workbooks 
    On Error GoTo abcd 
    x = wb.Name 
    Workbooks(x).Activate 
    If Range("Data").Address <> "" Then y = wb.Name 

    Exit Sub 

abcd: 
Next wb 

End Sub 

基本目標是找到一個Excel與特定的命名範圍文件時,我知道它的存在,但不知道該文件的名稱,因爲它改變每週或每月。目標是找到該文件並在該點退出該子文件(或者在該文件上執行其他代碼並退出而不是轉到其他文件)。

我發現它工作正常如果我只打開兩個文件但不能如果有更多的話(除非目標人排在第二位)。雖然我可以用我擁有的東西來運行,但我認爲其他人可能從我擁有的東西中受益,並且我可以擁有更強大的解決方案。

更新: 感謝所有向Mitch回覆&將原始文章以可讀格式發送的人! (我從那以後學會了如何糾正這個問題,並且能夠直接複製代碼 - 我在下面的一些評論中指出,我遇到了麻煩。) 我已經獲得了不同程度的成功 - 來自PaulStock的代碼& Reafidy最初爲我工作,但PaulStock代碼已停止爲我工作。迴應& Jean-FrançoisCorbett和Chris Neilsen的代碼對我很有幫助,但是現在當我運行代碼時(按原樣),它看起來什麼都不做 - 即不會離開我運行它的工作表(而且那不是範圍名稱數據出現)。我最初是在Excel 2007中的代碼中使用其他宏運行代碼,但爲了嘗試獲得不同的結果,將它們移到了獨立表單中,但沒有打開其他宏文件。也嘗試從保存爲'97 -'03格式的文件運行它們。沒有得到不同的結果。其他人比我有更多的經驗(請參閱我在Reafidy &的意見討論中證明的錯誤)請記住,我的原始發佈代碼是通過谷歌搜索到的材料的結果,並且由我修改以用於特定任務&應用程序和暗示我不懂足以讓我自己想出)可能會發現更好的其他解決方案,但現在:

我非常高興,因爲Reafidy的代碼適合我。

由於我沒有註冊(我做了嘗試但沒有成功),但沒有足夠的聲望點,我無法投票,但我在Reafidy的解決方案旁邊放了一個複選標記。

進一步更新: 我現在已經發現,PaulStock &讓·弗朗索瓦·科貝特的代碼是不是爲我工作,由於我的一個非常小的差異 - 代碼包含的「數據」,而我的命名範圍爲「數據」 。在他們的代碼中進行這種更改(以便區分大小寫)意味着他們的兩種解決方案現在都適用於我,因此我試圖在其解決方案中添加一個刻度!不幸的是,我發現只有一種解決方案可以打勾。

我也學到了,我把克里斯的代碼字面上。試圖按照原樣測試每個代碼,這就是我所做的。在'有東西'的部分添加一個簡單的'wb.activate',可以讓代碼做我想做的事情。

再次感謝所有四個貢獻。

+0

@Derek,請看到我的編輯。 – Reafidy

回答

4

你在代碼中做了一些令人費解的事情,我認爲這就是令人困惑的問題。

讓你錯誤處理程序(abcd:)在For...Next循環的中間開始是非常糟糕的做法,只會導致混淆。我想不出爲什麼要這樣做。

無論如何,沒有必要爲此任務使用錯誤處理。我知道有一些例外的情況,糟糕的VBA設計迫使我們使用錯誤處理而不是內置的VBA功能(例如測試是否爲非變體array has been allocated),但這不是其中之一。有一個標準的方法來做到這一點(.Names工作簿對象的集合),並使用錯誤處理,而不是這是混亂和錯綜複雜,並要求麻煩。

另外,爲什麼說

x = wb.Name 
Workbooks(x).Activate 

時,你可以說wb.Activate?你沒有使用x作任何事情。或者y

下工作,是既簡化和優化,相對於原來的代碼,以及對已放棄了到現在爲止其他答案:

Sub zaa2() 
    Dim wb As Workbook 
    Dim nm As Name 

    For Each wb In Workbooks 
     For Each nm In wb.Names 
      If nm.Name = "Data" Then 
       wb.Activate 
       Exit Sub 
      End If 
     Next 
    Next wb 
End Sub 
' A workbook containing a range named "Data" is now activated 
' (if one is found amongst the open workbooks). 
' Note that there may be more than one, but only the first found is activated... 

編輯:在你的評論,你提到由於大寫"Data"和小寫"data"之間的混淆,您遇到了麻煩。爲了在將來防範這種情況,一種可能性就是忽略病例。這可以做如下:

If StrComp(nm.Name, "data", vbTextCompare) = 0 Then 

If LCase(nm.Name) = "data" Then 

都返回True如果nm.Name"Data""data""dATa"

+0

你的關於wb.activate的邏輯聽起來不錯,因此我會同意不需要x。然而,Y在其他地方使用(在其他與基本問題無關的代碼中)。底線雖然是上面沒有爲我工作。也許我在做什麼? – Derek

+0

+1建議避免日常任務的錯誤處理。 –

+0

定義「沒有工作」。我測試了它,並且在這方面效果很好。 –

1

你不能使用那樣的錯誤處理。任一移動至錯誤處理跳出循環或每次出現時重置錯誤處理程序,所以使用錯誤處理是這樣的:

一個更優選的替代方案將是:

Sub Test() 

    For Each wb In Workbooks 
     x = wb.Name 
     Workbooks(x).Activate    

     If RangeExists("Data") Then 
      y = wb.Name 
      Exit Sub 
     End If 

    Next wb 

End Sub 
Function RangeExists(s As String) As Boolean 
    On Error Resume Next 
    RangeExists = Range(s).Count > 0 
End Function 

編輯:

@ Jean-FrançoisCorbett,我不得不說你很快就跳下了投票按鈕。我發佈的第一個解決方案是因爲我假定OP沒有發佈他的整個代碼,所以我沒有試圖簡化它或者像我通常那樣「清理它」。我同意我沒有把我的回答說得很好,但是關於第一個解決方案,我試圖證明他需要重置錯誤處理程序。不幸的是,我應該說一個「最好的選擇是」。

@Derek,對不起,我無法及時回答您的進一步問題。顯然你可以自由選擇你喜歡的任何方法。在我看來,其他人提供的多循環解決方案深入到工作簿名稱集合中是不必要的,並且冗長的囉嗦。現在更重要的是,名稱集合可以包含引用常量,公式或範圍的名稱。我假設你只想檢查定義的名稱是否是特定的命名範圍,這意味着其他人提供的循環方法需要調整爲可靠。

我同意別人的意見,應該避免錯誤處理,但在Excel中不必要的循環可能與使用錯誤處理一樣邪惡,我個人會避免它像鼠疫一樣。

上面的功能可以放在自己的模塊中,並可以隨意使用。它快速,可靠,避免不必要的循環,特別檢查工作簿中的命名範圍,並且是檢查excel vba社區內是否存在命名範圍的最廣泛接受/使用的方法(我的意思是使用函數和錯誤處理通過名稱集合循環)。做一個谷歌搜索「檢查如果命名範圍存在」,如果你不相信我。或者訪問www.ozgrid.com/forum詢問是否需要其他excel vba專家的意見。

現在,我知道你已經張貼整個代碼,並且您不打算激活每一個工作簿時,您可以使用此代碼,將啓動與指定範圍內的「數據」中發現的第一個工作簿:

Sub Test3() 
    Dim wbLoop As Workbook 

    For Each wbLoop In Workbooks 
     If RangeExists("data", wbLoop) Then 
      wbLoop.Activate 
      Exit Sub 
     End If 
    Next wbLoop 

End Sub 
Function RangeExists(s As String, wb As Workbook) As Boolean 
    On Error Resume Next 
    RangeExists = wb.Names(s).RefersToRange.Count > 0 
End Function 

我完全理解積極批評的必要性,如果使用正確,我相信投票制度是正確的。然而,我相信這是一個合理的解決方案,並與我在操作系統格式化問題上的幫助相比,我有兩次反對票 - 不幸的是,我不能幫助,但我覺得我想遠離這個論壇。

+0

欣賞這些回覆,因爲我是第一個承認我的代碼很少缺乏波蘭語的人。試了兩個以上,並得到編譯錯誤 結束如果沒有塊如果 兩個。如果我刪除了代碼行結束並再次運行它,結果與我原來的代碼基本相同 - 只有在打開工作表的第二行時才找到正確的工作表。只有當它沒有找到正確的工作表時沒有告訴我有錯誤,只是留在第一張 – Derek

+0

嗨Derek,上面的代碼不會引發編譯錯誤。您要麼不正確地複製代碼,要麼已經在某種程度上對其進行了修改。 – Reafidy

+0

您應該爲此過程發佈完整的代碼,然後我們可以幫助進一步改進我們的解決方案。 – Reafidy

1

繼承人沒有得到花哨的錯誤處理程序

Sub zaa() 
    Dim wb As Workbook 
    Dim CheckForNamedRange As Boolean 
    Dim nm As Name 

    On Error GoTo EH 

    For Each wb In Workbooks 
     CheckForNamedRange = True 
     Set nm = wb.Names("data") 
     If CheckForNamedRange Then 
      ' Name found 
      ' do stuff 

      Exit For 
     End If 
    Next 
Exit Sub 
EH: 
    If CheckForNamedRange Then 
     ' Name not found 
     Err.Clear 
     CheckForNamedRange = False 
     Resume Next 
    Else 
     ' Some other error occured, so handle it 
     '... 
    End If 
End Sub 
+0

不知道我是否做錯了什麼,但是當我測試它時,它似乎什麼都不做。請注意,當我嘗試從這裏複製代碼時,它不會保留相同的格式,因此我將它粘貼到單詞上,將事情放在正確的行上,然後複製到vba&run中。我並不擔心佈局,因爲我相信這只是關於更好的可讀性而不是代碼功能。 – Derek

+0

「沒有想到錯誤處理程序」 - 你在開玩笑嗎?當然,看起來比其他所有方法都好看。 :) – Reafidy

+0

而且 - 去全黑人! – Reafidy

1

一種替代方法試試這個代碼。不應該擔心得到錯誤。

Sub zaa() 
    For Each wb In Workbooks 
     x = wb.Name 
     Workbooks(x).Activate 
     For Each n In Workbooks(x).Names 
      If n.Name = "Data" Then 
       y = wb.Name 
       Exit Sub 
      End If 
     Next 

    Next wb 
End Sub 
+0

仍然有編譯錯誤 如果沒有塊如果 結束,但當我從代碼中刪除「結束如果」行,它完美的工作(只要'數據'是一個打開的文件中的有效範圍) – Derek

+1

你不應該得到那個錯誤,保羅的代碼是正確的。我有一種感覺,你把「y = wb.name」放在與「If n.Name =」Data「」不一致的同一行上。它必須在自己的路線上。 – Reafidy

+0

應該是'Exit Sub',而不是'Exit For'。否則,它將循環遍歷所有工作簿,而不管是否找到「數據」。 +1時,這是糾正! –

相關問題