Z pomocą przychodzi debugowanie. Nazwa jest może trochę niefortunna, ale powszechnie używana w Polsce. Jest to proces uruchamiania programu krok po kroku w celu znalezienia błędów (bugów) lub po prostu przeanalizowania działania programu.
Powyższa, nieco lakoniczna definicja może być niezrozumiała. Spróbujmy więc debugowania samodzielnie, krok po kroku.
Stwórzmy nowy skoroszyt z najprostszym makrem:
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 |
Option Explicit Const gs_EdytowanyZakres As String = "A1:A10" Sub test() Dim lr_Komorka As Range Dim i As Integer Range(gs_EdytowanyZakres).Clear For Each lr_Komorka In Range(gs_EdytowanyZakres) If lr_Komorka.Row Mod 2 = 0 Then lr_Komorka = losowa_liczba Else lr_Komorka = nr_wiersza(lr_Komorka) End If Next lr_Komorka msgbox "Skonczyłem pracę!" End Sub Function losowa_liczba() As Integer losowa_liczba = Rnd() * 1000 End Function Function nr_wiersza(ir_komorka As Range) As Integer nr_wiersza = ir_komorka.Row End Function |
Powyższy program przegląda dziesięć komórek i wpisuje numer wiersza lub losową liczbę, zależnie, czy numer wiersza jest parzysty, czy nie. Po uruchomieniu makra w ułamku sekundy komórki wypełniają się liczbami i pojawia się komunikat. Chcielibyśmy jednak krok po kroku przeanalizować działanie programu.
Ustawianie breakpoint
W tym przypadku także posługiwać się będę popularną anglojęzyczną nazwą breakpoint. Można to najłatwiej przetłumaczyć jako punkt przerwania, przerwania działania programu, Breakpoint ustawiamy na jednej z linii naszego programu. Jeżeli program dotrze do tej linii, zatrzyma wykonanie i przeniesie nas do VBE.
Break point ustawiamy na dwa sposoby:
Kliknięcie prawym klawiszem na linię |
Kliknięcie lewym klawiszem na pasek z lewej strony |
Jak widać nasza linia została zaznaczona na czerwono, oraz z lewej pojawiła się czerwona kropka.
Spróbujmy teraz uruchomić nasze makro. Możemy to zrobić jednym ze sposobów przedstawionych wcześniej lub klawiszem F5, albo zielonym klawiszem Play (omówiony poniżej). Komunikat zakończenia działania nie pojawia się, za to edytor VBE wygląda jak poniżej. Linia, w której ustawiliśmy breakpoint jest zaznaczona na żółto i pojawiła się z lewej strony żółta strzałka. W ten sposób jest oznaczona linia, która wykona się następna, jeżeli pozwolimy programowi wykonać się dalej.
Działanie programu przerwane na zaznaczonej linii |
Kontrolowanie przebiegu programu
Spójrzmy teraz na ikony na górnym pasku.
Ikonki te pozwalają nam kontrolować przebieg programu. Kliknięcie ikonki „play” kontynuuje działanie. Wykona się zaznaczona linia i wszystkie kolejne, aż znowu napotkany zostanie breakpoint lub program zakończy działanie. Ikonka stop przerywa działanie makra.
Po kliknięciu play pojawi się nasz komunikat, po kliknięciu stop nie dzieje się nic, ponieważ nie wykona się linia wyświetlająca MsgBox.
Ustawmy teraz breakpoint na poniższej linii i uruchommy makro:
1 |
For Each lr_Komorka In Range(gs_EdytowanyZakres) |
Zaznaczona linia jest zaznaczona na żółto i oznaczona strzałką. Będziemy teraz analizować program krok po kroku. Można to robić przy pomocy kilku skrótów klawiaturowych, zobaczmy co się stanie po użyciu kolejnych skrótów:
F8
ctrl + shift + F8
Na ten wypadek zmodyfikowałem trochę nasz przykładowy program, funkcja zawiera kilka więcej poleceń.
F5
Wykonanie programu jest uruchamiane do momentu napotkania następnego breakpoint , Debug.Assert, stop (poniżej) lub zakończenia programu. Ten skrót działa tak samo jak naciśnięcie zielonej ikony play.
Ustawianie watch
Doskonałą funkcjonalnością VBE jest podglądanie wartości zmiennych podczas wykonywania programu. Watch’em może być dowolna zmienna, atrybut obiektu lub całe wyrażenie. Watch możemy ustawić przed uruchomieniem makra, lub już podczas wykonywania. Będę dalej posługiwał się angielską nazwą karkołomnie odmienianą w języku polskim.
Dodam teraz do naszego programu operację na zmiennej i, którą będziem obserwować
1 2 3 |
For Each lr_Komorka In Range(gs_EdytowanyZakres) i = i + 1 If lr_Komorka.Row Mod 2 = 0 Then |
Jeszcze przed uruchomieniem makra zaznaczam dowolne wystąpienie zmiennej i, klikam prawym klawiszem i wybieram Add Watch.
W okienku pod kodem (zatułowanym Watches) pojawiła się nowa linia.
W pierwszej kolumnie jest nazwa naszej zmiennej. W drugiej kolumnie nic nie jest napisane , program jeszcze się nie wykonuje więc nasza zmienna nie może mieć żadnej wartości. W trzeciej kolumnie (Type) pojawi się typ zmiennej, sami go zadeklarowaliśmy w programie. Ostatnia kolumna (Context) określa widoczność zmiennej (procedura test w module o nazwie sheet2).
Dla bardziej skomplikowanych zmiennych pojawia się struktura drzewa.
Powtórzmy dodawanie watch’a dla zmiennej lr_Komorka.
Ustawię teraz breakpoint na początku pętli FOR i uruchomię makro. Moje okno watches wygląda teraz tak jak powyżej.
Przed pierwszym wykonaniem pętli przy zmiennej lr_Komorka napisane jest Nothing ponieważ pierwsza komórka zakresu A1:A10 nie została jeszcze przypisana do lr_Komorka.Klawiszem F8 wchodzę do wnętrza pętli, zaszło już przypisanie pierwszej komórki zakresu Range(gs_EdytowanyZakres) do zmiennej lr_Komorka.
1 |
lr_Komorka = losowa_liczba(lr_Komorka) |
Dodawanie watch przez menu |
Podglądanie wartości zmiennych bez Watch’a
Podczas debugowania nie trzeba dodawać watchy, aby podejrzeć co jest pod określoną zmienną. Wystarczy najechać na nią myszką:
Klasa Debug
Wbudowana klasa debug udostępnia dwie metody przydatne do analizy programu. Pierwsza to print. Drukuje ona w okienku immediate edytora VBE. Jeżeli nie widzisz okna immediate, włącza się w górnym menu: view/immediate window.
Dodaj dodatkową linię do programu:
1 2 |
lr_Komorka = losowa_liczba(lr_Komorka) Debug.Print lr_Komorka |
Po wykonaniu całego programu w oknie immediate pojawią się kolejne wartość komórki przypisanej do lr_Komorka:
Druga metoda to debug.assert, służy ona do warunkowego zatrzymania programu. Program zostaje przerwany kiedy warunek umieszczony po assert przestaje być prawdziwy,
Polecenie:
1 |
Debug.Assert i < 5 |
spowoduje przerwanie działania programu kiedy i przestaje być mniejsze niż 5.
Oczywiście polecenie Debug.Assert False zawsze zatrzymuje program a Debug.Assert True nigdy programu nie przerwie.
Polecenie STOP
Polecenie Stop działa tak jak Debug.Assert False, czyli zawsze zatrzymuje działanie programu,
Oczywiście, jeżeli program piszemy dla kogoś innego należy usunąć polecenia stop i użycie klasy debug przed przekazaniem pliku.
Na koniec
Nie będę ukrywał, że poniższy wpis powstawał z dużymi przerwami przez parę miesięcy, mam nadzieję, że ilość informacji to czytelnikom wynagrodzi. Jeżeli znajdziecie powyżej jakieś błędy, braki, niekonsekwencje lub potrzebujecie dodatkowych wyjaśnień w którymkolwiek punkcie, proszę śmiało pisać.