09 - Instrukcje warunkowe


Tematem tej lekcji będą instrukcje warunkowe. Nauczymy się sterować wykonywaniem programu za pomocą warunku If ... Then, poznamy też operatory logiczne, których głównym zastosowaniem są właśnie instrukcje warunkowe.

Przy okazji, zgodnie z obietnicą z poprzedniej lekcji, nauczymy się jak zabezpieczyć aplikację przed wpisaniem przez użytkownika niewłaściwego typu danych w oknie InputBox oraz jak sprawdzić, który przycisk został wciśnięty przez użytkownika w oknie MsgBox i uzależnić od niego dalsze wykonywanie makra.

Sterowanie programem za pomocą warunków

Bardzo często zdarza się, że program ma wykonywać jakieś czynności, ale tylko wówczas, gdy spełnione są określone warunki.

Przykłady takich sytuacji wymieniono już w poprzedniej lekcji omawiającej komunikację z użytkownikiem. Jedną z nich było uzależnienie dalszego wykonywania makra od przycisku, który wcisnął użytkownik, drugą natomiast sprawdzanie, jaką wartość wpisał użytkownik w oknie InputBox, i wyświetlenie informacji o nieprawidłowym typie danych, jeżeli wpisano tekst zamiast liczby.

Poniżej znajduje się makro obliczające pensję netto, w której wartość pensji brutto jest pobierana od użytkownika za pomocą okna InputBox. Makro to było omawiane w poprzedniej lekcji i, jak wówczas wspomniano, nie miało żadnego zabezpieczenia przed wpisaniem przez użytkownika nieprawidłowego typu danych (np. tekstu xyz w miejscu, gdzie powinna być podana wysokość pensji brutto) - w takiej sytuacji makro po prostu przestawało działać, a na ekranie ukazywał się wygenerowany przez VBA komunikat z informacją o błędzie Run-time error '13': Type mismatch, co jest oczywiście zupełnie niezrozumiałe dla końcowego użytkownika.

W poniższym kodzie do makra dodano instrukcję warunkową, która w przypadku podania przez użytkownika nieprawidłowego typu danych wyświetla odpowiedni komunikat (wiersze kodu dodane w tej wersji makra zostały oznaczone na czerwono).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Sub zarobki()
    Dim s As String
    Dim pensjaBrutto As Long
    Dim pensjaNetto As Long

    s = InputBox("Podaj wysokość pensji brutto", "Pensja brutto")

    If IsNumeric(s) Then
        pensjaBrutto = s

        pensjaNetto = pensjaPoOpodatkowaniu(pensjaBrutto)

        Call MsgBox("Pensja brutto: " & pensjaBrutto & vbCrLf & _
            "Pensja netto: " & pensjaNetto, , "Pensja netto")
    Else
        Call MsgBox("Nieprawidłowa wartość pensji brutto" & _
            vbCrLf & "Podana wartość musi być liczbą", _
            vbOKOnly + vbExclamation, "Nieprawidłowa wartość")
    End If

End Sub
1
2
3
Function pensjaPoOpodatkowaniu(podstawa As Long) As Long
    pensjaPoOpodatkowaniu = podstawa - (podstawa * 0.18)
End Function

W sekcji deklaracji zmiennych, obok zmiennych pensjaBrutto i pensjaNetto, została jeszcze zadeklarowana pomocnicza zmienna typu tekstowego s. W omawianym przykładzie niezbędna jest właśnie zmienna tekstowa, tak by mogła być do niej przypisana dowolna wartość wprowadzona przez użytkownika w oknie InputBox. Wcześniej, kiedy wartość wpisana przez użytkownika była przypisywana bezpośrednio do zmiennej liczbowej pensjaBrutto, generowany był błąd w sytuacji, gdy użytkownik wprowadził wartość tekstową zamiast liczby.

W wierszu 6 do zmiennej s zostaje przypisany wynik działania funkcji InputBox, czyli wartość wpisana przez użytkownika. Zmienna s, jako zmienna typu tekstowego, może przyjąć każdą wartość nie generując przy tym żadnych błędów.

W wierszu 8 pojawia się wreszcie instrukcja warunkowa, będąca tematem dzisiejszej lekcji.

Postać ogólna instrukcji warunkowej przedstawia się następująco:
1
2
3
4
5
If [warunek] Then
    'instrukcje wykonywane, jeżeli warunek jest spełniony
Else
    'instrukcje wykonywane, jeżeli warunek nie jest spełniony
End If

Między słowami kluczowymi If oraz Then należy wstawić tzw. warunek, czyli działanie, którego wynikiem będzie wartość logiczna True lub False.

Jeżeli warunek określony w wierszu If ... Then jest spełniony zostaną wykonane instrukcje zawarte między linijkami If ... Then oraz Else (oznaczone na powyższym schemacie ogólnym instrukcji warunkowej zielonym komentarzem), a następnie wykonywanie makra przenosi się do końcowego wiersza instrukcji warunkowej - End If (pomijany jest więc blok instrukcji znajdujący się pomiędzy słowami kluczowymi Else a End If, oznaczony na powyższym schemacie na czerwono).

Analogicznie w sytuacji, gdy warunek zwróci wartość False - makro pomija blok instrukcji oznaczony na schemacie na zielono i przeskakuje do bloku poleceń umieszczonego pomiędzy linijkami Else oraz End If (oznaczonego na czerwono), a następnie kontynuuje swoje działanie za instrukcją warunkową.

Najczęściej jako warunki decydujące o dalszych losach wykonywania kodu wykorzystywane są zmienne typu Boolean lub funkcje zwracające taki typ danych.

Jak jednak wspomniano w lekcji czwartej, jeżeli zamiast wymaganej wartości logicznej kompilator natrafi na inny typ danych, próbuje automatycznie przekonwertować tę napotkaną wartość do wymaganego typu logicznego (tak samo zresztą dzieje się z innymi typami zmiennych). Dzięki tej automatycznej konwersji, jako warunek instrukcji warunkowej można podstawić również wszystkie liczby, teksty True oraz False, a także funkcje zwracające te wartości. Dla przypomnienia - jako wartość True interpretowane są wszystkie liczby różne od 0 oraz tekst True, natomiast tekst False oraz liczba 0 są równoznaczne z wartością logiczną False.

W związku z powyższym prawidłowe są na przykład takie zapisy:
If 0 Then (w tym przypadku warunek nie jest spełniony),
If 2 Then (warunek spełniony),
If -1 Then (warunek spełniony),
If 0.0132 Then (warunek spełniony),
If 2 * (4-5) Then (warunek spełniony),
If Sqr(5) Then (warunek spełniony),
If "True" Then (warunek spełniony),
If "False" Then (warunek nie jest spełniony).

Ale już na przykład zapis If "Prawda" Then spowoduje wygenerowanie błędu Run-time error '13': Type mismatch.

W powyższym przykładzie warunkiem rozpatrywanym przez wyrażenie If ... Then jest funkcja IsNumeric, w której jako argument podano zmienną s. Jak dowiedziałeś się w lekcji opisującej funkcje wbudowane funkcja IsNumeric zwraca wartość True, jeżeli argument jest liczbą lub tekstową reprezentacją liczby. Wartość False jest natomiast zwracana dla każdej innej wartości argumentu.

Dlatego też, jeżeli użytkownik wpisze w oknie InputBox tekst nie dający się przełożyć na liczbę lub pozostawi puste pole, funkcja IsNumeric zwróci wartość False i wykonywanie makra zostanie przeniesione do poleceń znajdujących się pomiędzy słowami kluczowymi Else a End If. W sekcji tej znajduje się tylko jedna instrukcja - wywołanie okna zatytułowanego Nieprawidłowa wartość z ikoną ostrzeżenia i komunikatem Nieprawidłowa wartość pensji brutto. Podana wartość musi być liczbą.

Jeżeli natomiast użytkownik wpisze w oknie InputBox wartość liczbową, wartość zmiennej s będzie tekstową reprezentacją liczby i funkcja IsNumeric zwróci wartość True. W takiej sytuacji aplikacja będzie kontynuowała swoje działanie wykonując polecenia zawarte w bloku znajdującym się pomiędzy linią If ... Then, a słowem kluczowym Else. Najpierw do zmiennej pensjaBrutto zostanie więc przypisana liczba reprezentowana przez tekst s (wiersz 9), a następnie wywoływana będzie funkcja pensjaPoOpodatkowaniu, w której argumentem jest właśnie ta liczba (wiersz 10). Ostatecznie makro wyświetli końcowy wynik w oknie z komunikatem, przedstawiając informacje o wysokości podanej przez użytkownika pensji brutto i wyliczonej na tej podstawie pensji netto (wiersze 12-13). Po wykonaniu wszystkich instrukcji znajdujących się w tym bloku, makro ominie blok przewidziany dla niespełnionego warunku i przejdzie do wiersza End If zamykającego instrukcji warunkowej (czyli do wiersza 18).

Zagnieżdżanie i zwijanie instrukcji warunkowych

Poniżej znajdziesz kolejny przykład zastosowania instrukcji If ... Then, w którym zaprezentowano dwie jej ważne cechy - możliwość zagnieżdżania jednego warunku w drugim oraz zwijanie całej instrukcji do jednej linijki.

Zaprezentowane makro wymaga najpierw od użytkownika podania liczby, a następnie wyświetla okno z komunikatem czy podana przez niego liczba jest parzysta. Przed sprawdzeniem parzystości liczby, podobnie jak w poprzednim przykładzie, zastosowano oczywiście zweryfikowanie poprawności podanej przez użytkownika wartości, gdyż niemożliwe byłoby sprawdzanie parzystości np. tekstu abc.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Sub zarobki()
    Dim s As String
    Dim opis As String

    s = InputBox("Podaj liczbę", "Liczba wejściowa")

    If IsNumeric(s) Then

        If s Mod 2 Then opis = "nieparzysta" Else opis = "parzysta"
        Call MsgBox("Podana przez Ciebie liczba jest " & opis, vbOkOnly)

    Else
        Call MsgBox("Nieprawidłowa wartość." & _
            vbCrLf & "Podana wartość musi być liczbą", _
            vbOKOnly + vbExclamation, "Nieprawidłowa wartość")
    End If

End Sub

W makrze zadeklarowane są zmienne tekstowe s oraz opis.

Do zmiennej s, podobnie jak w poprzednim przykładzie, przypisana zostanie wartość wprowadzona przez użytkownika. Zastosowanie w tej sytuacji zmiennej tekstowej ma na celu umożliwienie wpisania dowolnej wartości bez generowania komunikatów o błędzie w sytuacji, gdy wartość ta nie będzie liczbą.

Zmienna opis będzie natomiast przechowywać wynik operacji obliczania reszty z dzielenia podanej przez użytkownika liczby przez 2. Sensowność zastosowania w tej sytuacji zmiennej tekstowej zostanie wyjaśniona w dalszej części analizy kodu.

W wierszu 5 wyświetlone zostaje okno InputBox, w którym użytkownik powinien podać wybraną przez siebie liczbę. Następnie, w wierszu 7, makro sprawdza za pomocą funkcji IsNumeric czy podana przez użytkownika wartość jest liczbą, a więc czy można na niej wykonać operację obliczania reszty z dzielenia.

Jeżeli zmienna s nie przechowuje wartości liczbowej, wykonywanie makra zostaje przeniesione do wiersza 13 i wyświetlone zostaje ostrzeżenie o nieprawidłowym typie danych.

Jeżeli natomiast wartość podana w oknie InputBox jest liczbą, makro przechodzi do bloku zadań znajdującego się pomiędzy wierszem If ... Then a Else i zabiera się za sprawdzanie parzystości podanej liczby.

Najciekawszym wierszem omawianej aplikacji jest wiersz 9, zawierajacy instrukcję:
9
If s Mod 2 Then opis = "nieparzysta" Else opis = "parzysta"

Pierwszy wniosek, jaki nasuwa się na podstawie tej linijki kodu, to fakt, że instrukcje warunkowe If ... Then mogą być zagnieżdżane. Jak widzisz, instrukcja If znajdująca się w tym wierszu jest zagnieżdżona w instrukcji If rozpoczynającej się wiersz wyżej. Jak zobaczysz w dalszych lekcjach, zagnieżdżanie instrukcji warunkowych jest bardzo powszechną praktyką i nie ma tutaj żadnego ograniczenia jeżeli chodzi o liczbę poziomów zagnieżdżania i ich skomplikowanie - równie dobrze można byłoby dodać jeszcze instrukcję If w bloku wykonywanym w przypadku niespełnienia warunku, w niej jeszcze jedną instrukcję warunkową itd.

Kolejną rzucającą się w oczy rzeczą jest to, że cała instrukcja warunkowa If ... Then została umieszczona w jednym wierszu.

Umieszczenie całej instrukcji warunkowej w jednym wierszu jest możliwe tylko w jednej sytuacji: jeżeli czynności wykonywane zarówno w sytuacji spełnienia, jak i nie spełnienia warunku, mogą być opisane w pojedynczej linii kodu.

W opisywanej sytuacji w przypadku spełnienia warunku funkcji wykonywane jest tylko przypisanie tekstu nieparzysta do zmiennej opis. Podobnie w przypadku, gdy warunek nie jest spełniony, jedyną wykonywaną przez makro czynnością jest przypisanie do zmiennej opis tekstu parzysta.

Dla odmiany instrukcja warunkowa rozpoczynająca się w wierszu 7 nie może zostać zwinięta do jednego wiersza, ponieważ czynności wykonywane dla spełnionego warunku IsNumeric(s) obejmują dwie linijki kodu: zagnieżdżoną pętlę warunkową (wiersz 9) oraz wywołanie okna z komunikatem (wiersz 10).

Zauważ, że jeśli cała instrukcja warunkowa umieszczona jest w jednej linijce pomijane jest słowo kluczowe End If.

Zwijanie instrukcji warunkowej do jednej linijki nie powinno być nadużywane, aby nie wpływać negatywnie na czytelność kodu. Jedyną sytuacją, w której powinno się stosować ten zabieg, jest właśnie zaprezentowana tutaj instrukcja warunkowa, w której dla obu wyników warunku jedynymi operacjami jest przypisanie do jakiejś zmiennej wartości określonej wprost (a nie za pomocą funkcji, gdyż wówczas cały wpis jest zazwyczaj zbyt rozwlekły i nie mieści się na szerokości ekranu).

Dokładniejszego omówienia wymaga też warunek podany dla instrukcji If wywoływanej w wierszu (9). Zastosowanie znajduje tutaj zasada opisana na początku lekcji, mówiąca o tym, że warunkiem instrukcji If może być też operacja matematyczna albo funkcja, jeżeli jej wynikiem będzie liczba lub teksty True i False. Dla przypomnienia dla tekstu False oraz liczby 0 warunek przyjmuje wartość False, natomiast dla tekstu True oraz każdej innej liczby - warunek jest spełniony.

W tej konkretnej sytuacji warunkiem jest operacja obliczania reszty z dzielenia liczby podanej przez użytkownika (przechowywanej w zmiennej s - jest to wprawdzie zmienna tekstowa, ale przy zastosowaniu jej w operacji Mod zostaje automatycznie przekonwertowana do liczby całkowitej) przez liczbę 2.

Dla liczb parzystych wynikiem tego działania będzie 0, co jest równoznaczne ze zwróceniem przez warunek wartości False.

Resztą z dzielenie liczb nieparzystych przez 2 będzie natomiast 1, a więc warunek umieszczony w sekcji warunkowej instrukcji If będzie spełniony i zwróci wartość True.

W związku z powyższym - jeżeli dla liczb nieparzystych warunek zwróci wartość True, a dla parzystych False - w bloku opisującym czynności dla spełnionego warunku do zmiennej opis należy przypisać tekst nieparzysta, natomiast w bloku dla niespełnionego warunku - tekst parzysta.

W wierszu 10 wywoływana jest funkcja MsgBox, która w zależności od wyniku obliczenia reszty z dzielenia, wyświetla na ekranie okno z komunikatem Podana przez Ciebie liczba jest parzysta lub Podana przez Ciebie liczba jest nieparzysta.

Warto jeszcze krótko uzasadnić sensowność wykorzystania w tym makrze zmiennej tekstowej opis.

Gdyby w makrze zabrakło tej zmiennej, zamiast tych dwóch wierszy:
9
10
If s Mod 2 Then opis = "nieparzysta" Else opis = "parzysta"
Call MsgBox("Podana przez Ciebie liczba jest " & opis, vbOkOnly)
należałoby wstawić poniższy blok instrukcji:
 
 
 
 
 
If s Mod 2 Then
    Call MsgBox("Podana przez Ciebie liczba jest nieparzysta", vbOkOnly)
Else
    Call MsgBox("Podana przez Ciebie liczba jest parzysta", vbOkOnly)
End If

Jedyną zaletą takiego rozwiązania byłoby zmniejszenie liczby zmiennych używanych w aplikacji z dwóch do jednej. Jednak operacja obliczenia reszty z dzielenia i wyświetlenia komunikatów wydłuża się w takiej sytuacji z dwóch linijek do pięciu. Ponadto wobec braku zmiennej opis, dwukrotnie powtórzona jest niemal identyczna operacja:
 
Call MsgBox("Podana przez Ciebie liczba jest ...", vbOkOnly)
która w obu przypadkach różni się tylko ostatnim słowem komunikatu, uzależnionym od wyniku operacji s Mod 2 (jak już zostało podczas tego kursu wielkorotnie wspomniane - każda sytuacja, w której powtarzany jest taki sam fragment kodu jest niepożądana).

W omówionej wersji makra, wykorzystującej dodatkową zmienną tekstową opis, ostatnie słowo komunikatu jest przypisywane właśnie do tej zmiennej, a funkcja MsgBox wywoływana jest z komunikatem będącym połączeniem tekstu wspólnego dla obu sytuacji: Podana przez Ciebie liczba jest oraz tekstu przechowywanego w zmiennej opis (a więc parzysta lub nieparzysta).

Pomijanie bloku Else

Często zdarza się, że instrukcja warunkowa If ... Then ma wykonywać jakieś czynności tylko w sytuacji, kiedy warunek jest spełniony, natomiast w przypadku niespełnienia warunku powinna po prostu przejść do kolejnych poleceń, znajdujących się za instrukcją warunkową (a więc za słowem kluczowym End If, które ją zamyka).

W takiej sytuacji można oczywiście pozostawić puste miejsce w bloku, w którym powinny znaleźć się instrukcje do wykonania w razie niespełnienia warunku, tak jak w poniższym przykładzie:
 
 
 
 
If x > 0 Then
    Call MsgBox("Liczba x jest większa od zera")
Else
End if

W powyższej instrukcji warunkowej w sytuacji, gdy liczba x jest większa od zera, zostaje wyświetlona informacja o treści Liczba x jest większa od zera. Natomiast dla liczb niedodatnich, wykonywanie kodu przenoszone jest do bloku pomiędzy słowami kluczowymi Else a End If. Nie napotyka tam jednak żadnych poleceń, więc przechodzi od razu do polecenia End If, zamykającego całą instrukcję warunkową.

W takim wypadku jak powyżej słowo kluczowe Else może, a nawet powinno być pominięte, a cały zapis powinien wyglądać tak jak poniżej:
 
 
 
If x > 0 Then
    Call MsgBox("Liczba x jest większa od zera")
End If

W takiej sytuacji można też zastosować opisane wcześniej zwijanie wierszy, a więc cała powyższa konstrukcja równie dobrze mogłaby wyglądać tak:
 
If x > 0 Then Call MsgBox("Liczba x jest większa od zera")

Niedopuszczalna jest natomiast sytuacja, w której to słowo kluczowe Then zostałoby pominięte. Słowo kluczowe Then zawsze musi pojawić się w tej samej linijce kodu, w której znajduje się słowo If oraz warunek (oczywiście można rozbić ten wiersz za pomocą operatora _). Zresztą w przypadku pominięcia słowa kluczowego Then lub umieszczenia go w niewłaściwej linii kodu, edytor VBA podświetli całą tę linię na czerwono i nie dopuści do uruchomienia makra.

W instrukcji warunkowej, która ma wykonywać jakieś polecenia tylko w razie niespełnienia warunku, po prostu nie umieszcza się żadnego kodu w bloku pomiędzy linijką If ... Then a Else, nie można jednak w takiej sytuacji pomijać żadnego elementu całej konstrukcji:
 
 
 
 
If x > 0 Then
Else
    Call MsgBox("Liczba x jest mniejsza od zera")
End If

Zamiast tego można jednak odwrócić wynik warunku za pomocą operatora Not() (operatory logiczne wykorzystywane w instrukcjach warunkowych zostały omówione w kolejnym podrozdziale tej lekcji). Wówczas to, co dotychczas było prawdą, stanie się fałszem i na odwrót, a operacje wykonywane dotychczas przy niespełnionym warunku będą teraz wykonywane przy jego spełnieniu:

 
 
 
 
If Not(x >= 0) Then
    Call MsgBox("Liczba x jest mniejsza od zera")
Else
End If

W powyższym kodzie można się już pozbyć słowa kluczowego Else, a dodatkowo zwinąć całą instrukcję warunkową do jednej linijki:
 
If Not(x >= 0) Then Call MsgBox("Liczba x jest mniejsza od zera")

Operatory logiczne

Określając warunek dla instrukcji If ... Then można konstruować rozbudowane warunki, składające się z kilku prostych warunków połączonych ze sobą za pomocą operatorów logicznych.

Kilka z operatorów logicznych dostępnych w VBA ma swoje odpowiedniki wśród funkcji arkuszowych, więc możesz je już znać (np. LUB() czy ORAZ()). Są one często wykorzystywane do budowania warunków dla arkuszowej funkcji warunkowej =JEŻELI()).

Poniższa lista zawiera wykaz wszystkich operatorów logicznych dostępnych w VBA. Klikając w nazwę poszczególnych operatorów przeniesiesz się do ich szczegółowego opisu z przykładami zastosowania.

Operator negacji (Not)

Operator Not stosowany jest wraz z pojedynczym wyrażeniem i odwraca jego wartość.

Operator Not działa identycznie jak funkcja arkuszowa =NIE. Jeżeli wynikiem jakiegoś wyrażenia jest True to dodanie przed nim operatora Not zmieni jego wartość na False i odwrotnie.

Poniżej znajduje się kilka przykładów zastosowania operatora Not w instrukcjach If ... Then.

 
If Not(x = 0) Then

Sam warunek x = 0 byłby spełniony dla zera, natomiast dla każdej innej liczby zwróciłby wartość False. Jednak dodanie przed nim operatora Not sprawia, że sytuacja odwraca się o 180 stopni.

Teraz w przypadku, gdy zmienna x ma wartość 0 całe wyrażenie warunkowe jest fałszywe, a więc wykonywane będą operacje umieszczone w bloku zawartym między słowami Else a End If.

Jeżeli zmienna x będzie natomiast miała wartość różną od 0, warunek będzie spełniony i wykonane zostaną polecenia znajdujące się pomiędzy słowami Then a Else.

 
If Not(2 > 1) Then

W tej sytuacji instrukcja If zawsze będzie wykonywała operacje przewidziane dla niespełnionego warunku. Wyrażenie 2 > 1 zawsze jest prawdziwe, jednak operator Not zamienia jego wartość na False.

 
If Not(Len(nazwa)) Then

Zmienna nazwa musi być zmienną tekstową, ponieważ tylko taki typ danych jest przyjmowany przez funkcję Len.

Funkcja Len(nazwa) zwraca długość tekstu przechowywanego w zmiennej nazwa.

Pamiętając o zasadzie konwersji liczby 0 na wartość logiczną False, a każdej innej liczby na True, można stwierdzić, że jeśli zmienna nazwa jest pustym ciągiem znaków (a więc jej długość zwrócona przez funkcję Len wyniesie 0) wyrażenie Len(nazwa) jest równoważne False, natomiast jeżeli tekst przechowywany w zmiennej nazwa zawiera jakieś znaki (a więc funkcja Len zwróci liczbę większą od zera) wyrażenie Len(nazwa) jest równoważne wartości logicznej True.

Jednak wyrażenie Len(nazwa) jest dodatkowo ujęte w operator Not(), który odwraca jego wynik. Po uwzględnieniu tego operatora wyrażenie warunkowe jest spełnione dla pustych ciągów znaków, a fałszywe, jeżeli zmienna nazwa zawiera niepusty tekst.

Operator iloczynu logicznego (And)

Operator And łączy ze sobą dwa wyrażenia i tworzy z nich jedno złożone wyrażenie, które zwraca wartość True, jeżeli oba składowe wyrażenia są prawdziwe oraz wartość False, jeżeli co najmniej jedno z nich nie jest spełnione. Operator And działa identycznie jak arkuszowa funkcja =ORAZ.

Poniżej znajduje się kilka przykładów zastosowania operatora And w instrukcjach If ... Then:

 
If x > 0 And x Mod 2 Then
Przedstawiony w tym przykładzie złożony warunek składa się z dwóch warunków składowych: x > 0 oraz x Mod 2, połączonych operatorem And, oznaczającym że oba te warunki muszą być równocześnie spełnione, aby całe wyrażenie było prawdziwe.

Pierwsza składowa tego złożonego warunku - x>0 - określa, że wartość zmiennej x musi być większa od zera.

Drugim składnikiem jest wyrażenie x Mod 2, które zwraca resztę z dzielenia liczby x przez 2. Aby wartość tego składowego wyrażenia była prawdziwa, wynikiem funkcji x Mod 2 musi być liczba różna od zera (ponieważ liczba zero równoważna jest wartości False, a każda inna liczba wartości True), a więc liczba x musi być nieparzysta (dla liczb parzystych resztą z dzielenia ich przez 2 jest 0).

Patrząc łącznie na podany warunek można stwierdzić, że będzie on spełniony w sytuacji, gdy zmienna x przechowuje liczbę nieparzystą większą od zera.

 
If Len(tekst) >= 6 And Mid(tekst, 2, 1) = "a" Then

W tym przykładzie składowymi konstrukcji logicznej z operatorem And są wyrażenia: Len(tekst)>=6 oraz Mid(tekst, 2, 1).

Pierwsze z tych wyrażeń - Len(tekst) >= 6 - jest spełnione jeżeli długość zmiennej tekstowej tekst wynosi co najmniej 6 znaków.

W drugim wyrażeniu zastosowano funkcję Mid, która zwraca określony fragment podanego tekstu. W tym konkretnym przypadku funkcja Mid zwraca fragment tekstu przechowywanego w zmiennej tekst, o długości jednego znaku, rozpoczynający się od drugiego znaku tego tekstu (a więc zwraca drugi znak tego tekstu). Wyrażenie jest spełnione, jeśli wartość zwrócona przez funkcję Mid wynosi a, a więc jeżeli drugi znak wyrazu przypisanego do zmiennej tekst to litera a.

Podsumowując, cały powyższy warunek jest spełniony w sytuacji, gdy zmienna tekst przechowuje tekst o długości co najmniej 6 znaków, w którym drugi znak to a.

 
If x >= 10 And x <= 20 Then

Powyższy zapis jest bardzo popularnym zastosowaniem operatora And i polega na sprawdzeniu czy wartość zmiennej zawiera się w jakimś przedziale.

Pierwsza składowa całego wyrażenia jest prawdziwa dla liczb większych lub równych 10, natomiast druga dla liczb mniejszych lub równych 20. W związku z tym, całe wyrażenie jest prawdziwe, jeżeli zmienna x jest równocześnie >= 10 i <= 20, a więc jeśli zawiera się w przedziale 10-20.

Operator sumy logicznej (Or)

Operator Or łączy ze sobą dwa wyrażenia i tworzy z nich jedno złożone wyrażenie, które jest prawdziwe, jeżeli przynajmniej jedno składowe wyrażenia jest prawdziwe oraz fałszywe, jeżeli oba wyrażenia składowe są równocześnie fałszywe. Operator Or działa identycznie jak arkuszowa funkcja =LUB.

Poniżej znajduje się kilka przykładów zastosowania operatora Or w instrukcjach If ... Then:
 
If x < 10 Or x > 20 Then

Powyższy przykład jest odwrotnością ostatniego z przykładów przedstawionych przy okazji opisywania operatora And, w którym wartość True była zwracana, jeżeli liczba zawierała się w określonym przedziale.

Pierwsze składowe wyrażenie - x < 10 - jest spełnione, jeżeli zmienna x jest mniejsza od 10, drugie natomiast - x>20 - jest prawdziwe dla liczb większych od 20.

Oba wyrażenia są ze sobą połączone operatorem Or, dlatego też wystarczy aby jedno z tych wyrażeń było prawdziwe, a całe wyrażenie przyjmie wartość True. Aby zatem całe wyrażenie było prawdziwe, zmienna x może przyjąć wartość mniejszą od 10 lub większą od 20. Dla liczb z zakresu 10-20 całe wyrażenie zwróci wartość False, ponieważ żadna z tych liczb nie jest ani mniejsza od 10, ani większa od 20.

Z uwagi na to, że to wyrażenie jest dokładną odwrotnością wspomnianej funkcji używającej operatora And, można je również zapisać poprzez wstawienie jego pierwszej wersji (tej z operatorem And) do operatora Not:
 
If Not(x >= 10 And x <= 20) Then

 
If Weekday(Date, vbMonday) = 2 Or Weekday(Date, vbMonday) = 4 Then

Załóżmy, że napisałeś makro wykonujące jakiś raport, przy czym we wtorki i czwartki ma ono jeszcze wykonywać jakieś dodatkowe operacje - np. przesyłać ten raport do klientów.

W takiej sytuacji mógłbyś skorzystać z powyższej instrukcji warunkowej. Składa się ona z dwóch składowych wyrażeń, z których każde sprawdza czy aktualna data przypada w określonym dniu tygodnia.

Każde z tych cząstkowych wyrażeń korzysta z funkcji Weekday, która zwraca numer dnia tygodnia dla określonej daty i określonego dnia uważanego za początek tygodnia oraz z funkcji Date, która zwraca aktualną datę.

Całe wyrażenie jest prawdziwe, jeżeli przynajmniej jedno ze składowych wyrażeń jest prawdziwe (zresztą w tym przypadku w jednym czasie tylko jedno wyrażenie może być prawdziwe, ponieważ określony dzień nie może być równocześnie wtorkiem i czwartkiem), a więc jeżeli aktualny dzień zwrócony przez funkcję Date przypada na wtorek lub czwartek.

Operator wyłączenia (Xor)

Operator Xor łączy ze sobą dwa wyrażenia i tworzy z nich jedno złożone wyrażenie, które zwraca wartość True tylko wtedy, kiedy jedno składowe wyrażenia jest prawdziwe, a drugie fałszywe, oraz wartość False jeżeli oba składowe wyrażenia są prawdziwe albo oba są fałszywe. Operator Xor nie ma odpowiednika wśród funkcji arkuszowych.

Poniżej znajduje się przykład zastosowania operatora Xor w instrukcji If ... Then:
 
If i >= 0 Xor j >= 0 Then

Przedstawiona powyżej instrukcja warunkowa składa się z dwóch wyrażeń: i >= 0 oraz j >= 0 połączonych operatorem Xor. Każde ze składowych wyrażeń sprawdza czy jedna ze zmiennych jest ujemna.

Jak wcześniej wspomniano, wyrażenie zawierające operator Xor jest prawdziwe, jeżeli oba jego składniki zwracają różne wartości. Aby więc cały warunek był spełniony, zmienna i musi być dodatnia, a zmienna j ujemna, lub odwrotnie. W sytuacji, gdy obie zmienne będą miały taki sam znak, warunek nie będzie spełniony.

Operator równości (Eqv)

Operator Eqv jest dokładną odwrotnością operatora Xor. Warunek zawierający operator Eqv jest spełniony w sytuacji, gdy oba wyrażenia składowe zwracają tę samą wartość. Jeżeli natomiast jeden ze składowych warunków jest prawdziwy, a drugi fałszywy, całe wyrażenie jest fałszywe. Operator Eqv nie ma swojego odpowiednika wśród funkcji arkuszowych.

Ponieważ operator Eqv jest dokładną odwrotnością operatora Xor, każdy warunek wykorzystujący Xor można zapisać w inny sposób - zastępując operator Xor operatorem Eqv i wstawiając całe wyrażenie do operatora Not (zasada działa też oczywiście w odwrotną stronę - każde wyrażenie z operatorem Eqv można zastąpić takim samym wyrażeniem z operatorem Xor, wstawionym do operatora Not).

Poniżej znajduje się przykład zastosowania operatora Eqv w instrukcji If ... Then:
 
If i >= 0 Eqv j >= 0 Then

Powyższa instrukcja jest dokładną odwrotnością instrukcji zaprezentowanej przy okazji omawiania operatora Xor. Instrukcja ta również składa się z dwóch wyrażeń: i >= 0 oraz j >= 0, w których każde sprawdza czy jedna ze zmiennych jest ujemna.

Jako, że operatorem łączącym oba wyrażenia składowe jest Eqv, cały warunek będzie spełniony w sytuacji, gdy oba cząstkowe wyrażenia zwrócą tę samą wartość, a więc gdy obie zmienne będą liczbami ujemnymi, lub obie będą liczbami dodatnimi. Jeżeli jedna z tych dwóch zmiennych będziesz przechowywała liczbę dodatnią, a druga ujemną, całe wyrażenie zwróci wartość False.

Operator implikacji (Imp)

Operator Imp, zwany operatorem implikacji, łączy ze sobą dwa wyrażenia składowe i zwraca wartość False w sytuacji, gdy pierwsze wyrażenie jest prawdziwe, a drugie fałszywe, oraz wartość True w każdej innej sytuacji.

Poniżej znajduje się przykład zastosowania operatora Imp w instrukcji If ... Then:
 
If dataPlatnosci < Date() Imp czyZaplacono Then

Celem powyższego wyrażenia, złożonego z dwóch składowych warunków połączonych operatorem Imp, jest wychwycenie przeterminowanych płatności.

Pierwszy składowy warunek sprawdza czy zmienna dataPlatnosci, przechowująca, jak nietrudno się domyślić, wymaganą datę płatności, jest mniejsza od aktualnej daty (jeśli jest mniejsza, płatność powinna być już uiszczona). Drugi warunek jest natomiast po prostu zmienną logiczną i jest spełniony wówczas, gdy zmienna ta przechowuje wartość True.

Tak jak wcześniej zaznaczono, wyrażenia powiązane operatorem Imp są fałszywe, jeżeli pierwsze z nich zwraca wartość True, a drugie False. W każdej innej sytuacji wyrażenia takie są prawdziwe.

W powyższym przykładzie wyrażenie będzie więc fałszywe tylko w sytuacji, gdy minęła już wymagana data płatności (czyli warunek dataPlatnosci > Date() zwróci True), a jednocześnie płatność ta nie została jeszcze uregulowana (zmienna czyZaplacono=False). W związku z tym, w instrukcji warunkowej If ... Then w bloku przewidzianym dla niespełnionych warunków można np. umieścić komunikat MsgBox z informacją o konieczności wykonania płatności.

Imp jest jedynym operatorem, przy którym kolejność przedstawienia obu składowych wyrażeń ma istotne znaczenie i może wpłynąć na wynik.

Język VBA umożliwia również tworzenie jeszcze bardziej złożonych wyrażeń, wykorzystujących równocześnie kilka operatorów logicznych.

Do przykładu przedstawionego przy okazji omawiania operatora Or, w którym sprawdzano czy aktualna data przypada we wtorek lub czwartek, można równie dobrze dopisać dodatkowy dzień:
 
If Weekday(Date, vbMonday) = 2 Or Weekday(Date, vbMonday) = 4 Or Weekday(Date, vbMonday) = 5 Then

Wyrażenie wykorzystuje teraz dwa operatory logiczne Or, które łączą ze sobą trzy składowe warunki, i będzie spełnione także dla dat przypadających w piątek.

Poniższe wyrażenie wykorzystuje natomiast dwa operatory And:
 
If x >= 0 And x <= 20 And x Mod 2 Then

Jako że wszystkie części składowe tego wyrażenia są ze sobą połączone operatorami And, będzie ono prawdziwe tylko wtedy, gdy prawdziwe będą wszystkie jego składniki.

Jak więc się już pewnie domyślasz na podstawie poprzednich przykładów, wyrażenie to będzie spełnione, jeżeli zmienna x będzie nieparzystą liczbą z zakresu 0-20 (aby spełniony był pierwszy warunek - x >= 0 - zmienna x musi być większa od zera; drugi warunek - x <= 20 - jest spełniony, jeżeli zmienna x jest mniejsza od 20; wreszcie aby spełnić trzeci warunek - x Mod 2 - operacja zwracania reszty z dzielenia zmiennej x przez 2 musi zwrócić liczbę różną od zera, a więc zmienna x musi być nieparzysta).

Możliwe jest też oczywiście łączenie w jednym wyrażeniu różnych operatorów. Przykład takiego wyrażenia zaprezentowano poniżej:
 
If x < 0 Or x > 20 And x Mod 2 Then

W przedstawionym powyżej wyrażeniu wykorzystane zostały operatory Or i And. Na pierwszy rzut oka mogłoby się wydawać, że wyrażenie to jest odwrotnością poprzedniego, które było spełnione dla liczb nieparzystych z zakresu 1-20. W rzeczywistości jest jednak inaczej.

Podobnie, jak to ma miejsce w przypadku operatorów arytmetycznych, niektóre operatory logiczne mają wyższy priorytet od innych i są wykonywane przed nimi. Kolejność wykonywania operatorów logicznych jest dokładnie taka, w jakiej zostały one omówione w nieniejszym podrozdziale: Not / And / Or / Xor / Eqv / Imp.

W związku z tym, w omawianym przykładzie, złożonym z trzech składowych wyrażeń, jako pierwsze rozpatrywane są wyrażenia drugie i trzecie - x > 20 And x Mod 2, które łącznie będą spełnione dla nieparzystych liczb większych od 20.

Dopiero teraz wynik tego wyrażenia jest łączony z pierwszym składowym wyrażeniem (x < 0) za pomocą operatora Or. Użycie tego operatora oznacza, że wystarczy spełnienie jednego z warunków, aby spełnione było całe wyrażenie - wystarczy więc, że zmienna x będzie mniejsza od zera (nawet jeśli będzie parzysta), a całe wyrażenie zwróci wartość True.

Przedstawiony przykład pokazuje, że ignorowanie kolejności wykonywania działań na operatorach logicznych może prowadzić do wyników niezgodnych z zamierzeniami. Aby uniknąć tego typu kłopotów, podobnie jak w przypadku operatorów arytmetycznych, należy posłużyć się nawiasami.

Żeby omawiane wcześniej wyrażenie rzeczywiście było spełnione dla nieparzystych liczb spoza zakresu 1-20, musiałoby być zapisane w następujący sposób:
 
If (x < 0 Or x > 20) And x Mod 2 Then

W takiej postaci tego wyrażenia najpierw rozpatrywane są warunki znajdujące się w nawiasie, a więc x < 0 Or x > 20, i dopiero wynik tego podwyrażenia jest zestawiany za pomocą operatora And z warunkiem x Mod 20.

Poniżej przedstawiono jeszcze jeden przykład obrazujący różnicę wynikającą ze zmiany kolejności działań poprzez zastosowanie nawiasów.

 
 
If Not x >= 0 And x < 20 Then
If Not (x >= 0 And x < 20) Then

W pierwszym zapisie najpierw wykonywana jest operacja negacji, a więc warunek Not x >= 0 jest przez kompilator przekładany na wyrażenie x < 0. Dopiero ten zapis jest łączony za pomocą operatora And z drugim składowym warunkiem: x < 20. Wyrażenie to będzie więc prawdziwe, jeżeli zmienna x będzie przechowywała liczbę ujemną.

Natomiast w drugim zapisie jako pierwsza wykonywana jest operacja w nawiasie, która zwraca wartość True dla liczb z zakresu 0-20. Dopiero po uzyskaniu wyniku wyrażenia w nawiasie, jest on odwracany przez operator Not, w związku z czym całe wyrażenie będzie spełnione dla liczb niezawierających się w zakresie 0-20.

Odczytywanie przycisku wciśniętego przez użytkownika

Ostatnim zagadnieniem, poruszonym przy okazji omawiania instrukcji warunkowych, będzie odczytywanie wyniku funkcji MsgBox (czyli przycisku wciśniętego przez użytkownika w oknie z komunikatem), które również wykorzystuje konstrukcję If ... Then.

Poniżej znajduje się przykładowe makro, które wyświetla najpierw pytanie Czy chcesz wyświetlić w arkuszu aktualną godzinę?, a następnie, w zależności od wciśniętego przycisku(Yes lub No) wyświetla w arkuszu godzinę lub kończy swoje działanie.
1
2
3
4
5
6
7
8
9
10
Sub wyswietlanieDaty()
    Dim przycisk As Integer

    przycisk = MsgBox("Czy chcesz wyświetlić w arkuszu aktualną godzinę?", _
        vbYesNo + vbQuestion, "Potwierdzenie")

    If przycisk = 6 Then
        Cells(1, 1) = Time
    End If
End Sub

W omawianym makrze zadeklarowana została jedna zmienna typu liczbowego - przycisk, która będzie przechowywała wartość liczbową wciśniętego przez użytkownika przycisku.

Do każdego typu przycisku, jaki może pojawić się w oknie MsgBox przypisane są odpowiednie liczby, które zostały przedstawione w poniższej tabelce:
PRZYCISKWARTOŚĆ
OK1
Cancel2
Abort3
Retry4
Ignore5
Yes6
No7

Po kliknięciu w oknie MsgBox jakiegokolwiek przycisku, okno to znika z ekranu, a cała funkcja MsgBox zwraca taką wartość, jaka jest przypisana do tego przycisku.

Okno MsgBox wyświetlane w opisywanym przykładzie posiada dwa przyciski: Yes oraz No, a więc funkcja MsgBox może przyjąć wartość 6 (jeżeli zostanie wciśnięty przycisk Yes) lub 7 (jeżeli użytkownik wciśnie No).

W wierszu 5 znajduje się instrukcja warunkowa, sprawdzająca czy do zmiennej przycisk przypisana jest wartość 6, co byłoby równoznaczne z kliknięciem przycisku Yes. Jeżeli warunek ten jest spełniony, makro wyświetla w komórce arkusza informację o aktualnej godzinie. W sytuacji, gdy warunek z wiersza 5 nie jest spełniony, czyli wciśnięty został przycisk No, makro nie ma wykonywać żadnych operacji, pominięty więc został blok Else instrukcji warunkowej.

W jednej z kolejnych lekcji poznasz wreszcie przywoływane od jakiegoś czasu wartości wyliczeniowe, dzięki którym zamiast korzystać przy odczytywaniu wyniku funkcji MsgBox z niewygodnych i trudnych do zapamiętania liczb, będziesz mógł użyć dobrze opisanych nazw wyliczeniowych, takich jak np. vbYes lub vbNo.