Polecenie On Error występuje w VBA pod kilkoma różnymi postaciami. W gruncie rzeczy chodzi jednak o zmianę reakcji kompilatora na wypadek błędu. Błąd może zostać zignorowany, może nas przenieść do konkretnej etykiety lub może przywrócić domyślny sposób traktowania błędów.W tym artykule opiszę kiedy powinniśmy używać poszczególnych instrukcji.
On Error Resume Next
Polecenie, które nakazuje ignorować wszystkie błędy i wykonywać dalsze linie kodu.
Jest to instrukcja, która jest bardzo często nadużywana przez osoby, które dopiero zaczynają swoją przygodę z VBA. W praktyce spotykam się z wieloma przypadkami, w których kod rozpoczyna się od linii On Error Resume Next.
Celem takiego podejścia jest wykonanie makra za wszelką cenę do końca – od A do Z. Nie wyświetlają się okienka sygnalizujące błąd. Dla autora są one irytujące ale tak naprawdę niosą nieocenioną pomoc – pozwalają namierzyć problem.
Oczywiście taka programistyczna partyzantka jest wysoce naganna. Nie wiemy czy w trakcie działania makra pojawił się jakikolwiek błąd. Ignorujemy tą kwestię z premedytacją. W efekcie może się okazać, że np. nie zaczytaliśmy prawidłowo danych źródłowych lub zaczytaliśmy je źle. Ignorując błędy, po prostu tego nie wiemy.
Nigdy nie powinniśmy ignorować błędów w swoich makrach! Dają nam one cenne informacje i pozwalają szybko namierzyć problem.
Rodzi się pytanie. Gdzie i kiedy zatem stosować instrukcję On Error Resume Next?
Odpowiedź jest dość prosta. Można włączyć ją na chwilę (na jedną lub kilka linii kodu)
Kasacja arkusza
Chcemy skasować konkretny arkusz w pliku, więc zamiast sprawdzać czy taki arkusz w ogóle istnieje, można od razu spróbować go usunąć. Jeśli arkusza nie ma w pliku – nic się nie stanie.
1 2 3 4 5 6 7 |
On Error Resume Next Application.DisplayAlerts = False wksArkusz.Delete Application.DisplayAlerts = True On Error GoTo ObslugaBledu |
Dodanie elementu do kolekcji
Chcemy dodać unikatowy element do kolekcji, ale nie wiemy czy go już tam nie ma.
1 2 3 4 5 |
On Error Resume Next colKodyProduktow.Add Item:=sNazwaProduktu, Key:=sKodProduktu On Error GoTo ObslugaBledu |
Wyszukiwanie wpisu
Chcemy sprawdzić, w którym wierszu znajduje się szukany wpis.
1 2 3 4 5 6 7 |
On Error Resume Next lPozycjaReferencji = 0 lPozycjaReferencji = WorksheetFunction.Match( _ sReferencja, wksCeny.Range("A:A"), 0) On Error GoTo ObslugaBledu |
Prowokowanie błędu
Chcemy sprawdzić czy wystąpił błąd, aby wykonać dalsze instrukcje
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
On Error Resume Next Set wkbBudzet = Workbooks("Budżet_Roczny.xlsx") If Err <> 0 Then If Err.Number = 9 Then Set wkbBudzet = Workbooks.Open( _ Filename:="D:\Excel\Prowadzenie firmy\Budżet_Roczny.xlsx", _ ReadOnly:=False, UpdateLinks:=False) End If Err.Clear End If On Error GoTo ObslugaBledu |
On Error GoTo Etykieta
Powyższa instrukcja jest stosowana zazwyczaj na samym początku makra i bardzo często ponawiana po poleceniu On Error Resume Next.
Informuje ona, że w przypadku błędu, procedura powinna przejść do etykiety, która znajduje się zazwyczaj na końcu makra. Pełni ona dwie funkcje:
- Wyświetla informację na temat błędu. Dobrze aby była ona jak najbardziej pełna i zawierała:
– numer i opis błędu.
– nazwę modułu, procedury i linię kodu, w której wystąpił błąd - Przechodzi do innej etykiety, która „sprząta” (przywraca ustawienia domyślne, zeruje zmienne obiektowe itp.) i kończy działanie makra.
Rodzi się pytanie. Czy każde makro powinno posiadać obsługę błędów z przejściem do etykiety?
Według mnie nie każde, ale zdecydowana większość. Wyjątkiem mogą być bardzo proste makra, co do których jesteśmy w 100% pewni, że nigdy nie wygenerują błędu. Przykładem może być np. zmiana ustawień właściwości dla obiektu Application.
Poniżej wklejam fragment makra, które stara się przypisać zmienną wkbBudzet do otwartego pliku Budżet_Roczny.xlsx. Takiego pliku nie mam nawet na dysku, więc makro wygeneruje błąd w linii nr 2 i przejdzie do etykiety nazwanej ObslugaBledu. Najpierw wyświetli odpowiedni komunikat, a potem przejdzie do drugiej etykiety nazwanej Wyjscie.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
Public Sub PobierzDaneZBudzetuRocznego() Dim wkbBudzet As Workbook Const sPROC As String = "PobierzDaneZBudzetuRocznego" 'Aktywuj obsługę błędów na starcie 1 On Error GoTo ObslugaBledu 'Przypisz zmienną obiektową do pliku z budżetem 2 Set wkbBudzet = Workbooks("Budżet_Roczny.xlsx") Wyjscie: 3 Set wkbBudzet = Nothing 4 On Error GoTo 0 5 Exit Sub ObslugaBledu: 6 Application.ScreenUpdating = True 7 If gbDEBUG_TRYB Then Stop 8 MsgBox "Wystąpił błąd nr " & Err.Number & " (" & Err.Description & ")." & _ vbCr & vbCr & "Linia kodu nr " & Erl & " w procedurze " & _ "'" & sPROC & "' modułu '" & msMODUL & "'.", vbInformation, "BŁĄD!" 9 Resume Wyjscie End Sub |
On Error GoTo 0
To polecenie przywraca domyślny dla VBA sposób traktowania błędów, czyli możemy powiedzieć, że wyłącza obsługę błędów użytkownika.
Podobnie jak polecenie On Error GoTo Etykieta – często występuje w parze z On Error Resume Next. Osobiście jednak używam tej instrukcji bardzo rzadko, ponieważ wolę korzystać z własnej obsługi błędów typu On Error GoTo Etykieta.
Innym atrybutem On Error GoTo 0 jest zerowanie obiektu Err, który przechowuje informację na temat ostatniego błędu.