Z
drugiej lekcji dowiedzieliśmy się, że kod może być przechowywany w procedurach lub funkcjach.
Wszystkie dotychczas przedstawione przykłady opierały się jednak tylko na procedurach. Czas więc nadrobić zaległości i
poświęcić trochę czasu funkcjom.
W tej lekcji ponownie będzie też mowa o przekazywaniu argumentów do procedur - temat ten zostanie rozwinięty o argumenty opcjonalne.
Nauczymy się też korzystać z okna Immediate, dzięki któremu można jeszcze szybciej i wygodniej uruchamiać
makra oraz podglądać wartości zmiennych w momencie zatrzymania działania makra (a nawet bez jego zatrzymywania!).
Podstawy funkcji
Podstawową, a tak naprawdę jedyną, różnicą pomiędzy procedurą a funkcją jest fakt, że funkcja potrafi i powinna zwrócić
jakąś wartość, zmienną lub obiekt.
Dotychczas wywoływaliśmy tylko procedury, które miały w sobie zadeklarowane jakieś zmienne, wykonywały jakieś polecenia,
ale nie zwracały żadnej wartości na zewnątrz siebie.
Owszem, w przykładzie z porzedniej lekcji, widziałeś, że procedura może wpłynąć
na wartość zmiennej z innej procedury, jeżeli zmienna ta została do niej przekazana jako argument. Jednak ciągle nie jest
to zwracanie wartości, a tylko modyfikowanie otrzymanej zmiennej.
Aby trochę rozjaśnić cały temat, wróćmy do przykładu z poprzedniej lekcji, a mianowicie obliczania podatków. Kod tamtego
przykładu wyglądał tak jak poniżej:
1
2
3
4
5
6
7
Sub zarobki()
Dim pensja As Long
pensja = 2500
Call odliczeniePodatku(pensja)
End Sub
1
2
3
Sub odliczeniePodatku(podstawa As Long)
podstawa = podstawa - (podstawa * 0.18)
End Sub
Dla przypomnienia, makro to działało w następujący sposób: istniała jedna zmienna pensja
, do której na początku
przypisywany był zarobek brutto, następnie zmienną pensja
przekazywano do procedury odliczaniePodatku
,
w której od tej zmiennej odejmowany był podatek, i w efekcie zmienna wracała do bazowej procedury już w postaci netto.
Załóżmy jednak, że chcemy mieć w naszym programie dwie zmienne - pensjaNetto
oraz pensjaBrutto
i do każdej z nich przypisać odpowiednią wartość.
Na początku musimy oczywiście przypisać do zmiennej pensjaBrutto
wysokość pensji (niech ponownie będzie to 2500).
Teraz jednak zaczynają się schody. Gdybyśmy postąpili tak, jak w poprzednim przykładzie, i po prostu wywołali procedurę
odliczaniePodatku
podając jako argument zmienną pensjaBrutto
, to procedura ta zmieniłaby wartość
zmiennej pensjaBrutto
na 2050, natomiast zmienna pensjaNetto
ciągle miałaby wartość 0 - a więc
zupełnie niezgodnie z założeniami.
Poniżej znajduje się kod z takim błędnym rozwiązaniem, tak byś mógł go samodzielnie uruchomić i prześledzić (najlepiej
ustaw punkty zatrzymania
w każdej jego linijce i sprawdzaj po kolei co się dzieje ze zmiennymi).
1
2
3
4
5
6
7
8
Sub zarobki()
Dim pensjaBrutto As Long
Dim pensjaNetto As Long
pensjaBrutto = 2500
Call odliczeniePodatku(pensjaBrutto)
End Sub
1
2
3
Sub odliczeniePodatku(podstawa As Long)
podstawa = podstawa - (podstawa * 0.18)
End Sub
Jednym z rozwiązań tego problemu byłoby poniższe makro
(Również polecam wstawić punkty zatrzymania w każdej linijce i sprawdzać, co się dzieje ze zmiennymi.
Ogólnie zalecam stosowanie tej metody tak długo, aż osiągniesz wprawę pozwalającą jednym rzutem oka na kod zauważyć, co się
dzieje ze zmiennymi w każdym momencie wykonywania programu).
1
2
3
4
5
6
7
8
Sub zarobki()
Dim pensjaBrutto As Long
Dim pensjaNetto As Long
pensjaBrutto = 2500
Call odliczeniePodatku(pensjaBrutto, pensjaNetto)
End Sub
1
2
3
Sub odliczeniePodatku(podstawa As Long, pensjaNetto As Long)
pensjaNetto = podstawa - (podstawa * 0.18)
End Sub
Zaprezentowany powyżej kod wprawdzie działa, a nawet zwraca prawidłowe wyniki, są jednak pewne ale ...
Najpoważniejszym minusem takiego rozwiązania jest fakt, że procedura odliczeniePodatku
wymaga teraz
podania dwóch argumentów, w tym jednego, który absolutnie nie jest potrzebny.
Wyobraź sobie, że musiałbyś odpowiedzieć na takie oto pytanie: Jeżeli znana jest stała stawka do obliczania podatków (18%),
to jakie informacje są potrzebne, żeby móc obliczyć Twoją pensję netto?
Oczywiście odpowiedziałbyś, że jedyną potrzebną informacją jest pensja brutto. Zdajesz więc sobie sprawę,
że wymagana jest tylko jedna wartość - pensja brutto. Natomiast procedura odliczaniePodatku
w powyższym
przykładzie wymagałaby podawania dwóch zmiennych. Jedna z nich - pensjaNetto
- przekazywana jest jako
pusta zmienna, czego absolutnie nie powinno się robić!
Dlaczego jest to takie ważne? Otóż każde przekazanie argumentu do procedury kosztuje trochę pamięci i czasu obliczeń.
Oczywiście w skali jednego wywołania procedury są to mikrosekundy i nikt nie zauważy tego gołym okiem. Wyobraź sobie
jednak, że Twoje makro będzie musiało obliczyć taki podatek dla 30 tysięcy osób z okresu 10 lat. Wtedy ta procedura
będzie musiała być wykonana setki tysięcy razy, a czas zmarnowany na przekazywanie pustej zmiennej będzie już liczony
w minutach, a nie mikrosekundach.
Drugi minus takiego rozwiązania jest taki, że jest to po prostu mało przejrzyste rozwiązanie.
Może trudno to sobie w tym momencie wyobrazić, ale jeżeli nadal będziesz się zajmował programowaniem w VBA, to po
niedługim czasie jeden rzut oka na kod będzie pozwalał Tobie zauważyć wiele rzeczy, na przykład w którym miejscu
do zmiennych zostały przypisane wartości. Niestety przy zastosowaniu takiego rozwiązania bardzo ciężko wyłapać
miejsce, w którym zmienna pensjaNetto
przestaje mieć wartość 0 i przyjmuje swoją właściwą wartość.
Powyżej pokazano dwa nieprawidłowe rozwiązania, których nie powinieneś stosować w takich sytuacjach. Jedno z nich
wprawdzie zwracało prawidłowe wyniki, ale argumenty przedstawione przeciwko takiemu rozwiązaniu powinny przekonać
Cię do jego niestosowania.
W poniższej ramce przedstawione zostało wreszcie prawidłowe rozwiązanie tego problemu, które, jak się pewnie domyślasz,
wykorzystuje funkcję. Pod ramką z kodem znajdziesz natomiast jego szczegółowe omówienie.
1
2
3
4
5
6
7
8
Sub zarobki()
Dim pensjaBrutto As Long
Dim pensjaNetto As Long
pensjaBrutto = 2500
pensjaNetto = pensjaPoOpodatkowaniu(pensjaBrutto)
End Sub
1
2
3
Function pensjaPoOpodatkowaniu(podstawa As Long) As Long
pensjaPoOpodatkowaniu = podstawa - (podstawa * 0.18)
End Function
Z kodu całkowicie została usunięta procedura odliczaniePodatku
, w miejsce której pojawiła się funkcja
pensjaPoOpodatkowaniu
.
Całe makro składa się teraz z procedury zarobki
oraz funkcji pensjaPoOpodatkowaniu
.
W procedurze zarobki
zadeklarowane są dwie zmienne typu Long
- pensjaBrutto
i
pensjaNetto
.
W wierszu 5 do zmiennej pensjaBrutto
przypisana zostaje wartość 2500. W tym momencie
jedynym zadaniem, jakie pozostało jeszcze do wykonania, jest obliczenie pensji netto i przypisanie jej do zmiennej
pensjaNetto
. Zadanie to zostanie wykonane przez wspomnianą funkcję.
Funkcję możesz sobie wyobrazić jako skrzynkę, do której wrzucane są argumenty, następnie skrzynka ta wykonuje
jakieś obliczenia i inne operacje, a w efekcie zwraca tylko jedną wartość, którą można potem przypisać do
jakiejś zmiennej albo wykorzystać w jakiś inny sposób (na przykład wyprintować w arkuszu).
W szóstej linijce opisywanego przykładu określono, że do zmiennej pensjaNetto
przypisane zostanie to,
co będzie wynikiem działania funkcji pensjaPoOpodatkowaniu
przy określonej wartości argumentów (w tym
przypadku argument pensjaBrutto
wynosi 2500).
W momencie, w którym makro napotyka w swoim kodzie na funkcję, przenosi wykonywanie kodu do tej funkcji i powróci
do procedury zarobki
po jej zakończeniu.
Szczegółowego omówienia wymaga budowa i działanie samej funkcji.
Jak już wspominałem podczas drugiej lekcji, słowem kluczowym otwierającym
funkcję jest Function
. Po tym słowie następuje nazwa funkcji
(zasady nazywania funkcji są takie same jak omówione już wcześniej
zasady nazywania procedur).
Następnie należy w nawiasie wymienić argumenty niezbędne do obliczenia tej funkcji wraz z podaniem ich typu.
Oczywiście czasem zdarzają się funkcje, które nie posiadają żadnych argumentów wejściowych - wówczas nawias
pozostaje pusty.
Ostatnim elementem wiersza otwarcia funkcji jest podanie słowa kluczowego As
oraz typu wartości
jaki jest zwracany przez tę funkcję.
Ogólna postać wiersza otwarcia funkcji wygląda więc następująco:
Function nazwaFunkcji([arg1 As typ,
..., argN As typ]) [As typFunkcji]
Jeżeli w wierszu otwarcia funkcji nie podasz typu zwracanej wartości, edytor VBA będzie ją domyślnie traktował
jako typ Variant
, co, jak już wspomniano w lekcji poświęconej
typom zmiennych, może znacznie obciążyć pamięć komputera i spowolnić działanie całego makra.
W powyższym przykładzie funkcja została nazwana pensjaPoOpodatkowaniu
, tak aby od razu było widać,
co takiego zwraca w wyniku. Funkcja otrzymała typ Long
, dzięki czemu otrzymany wynik będzie zaokrąglany
do części całkowitych. Jako argument podawana jest natomiast jedyna informacja potrzebna do jej wyliczenia, czyli
zmienna pensjaBrutto
, która również jest zmienną typu Long
.
Uważaj na określanie typów argumentów oraz typ zwracanej wartości!
Jeżeli w wierszu otwarcia funkcji podasz np. że wymaga ona argumentu liczbowego, a wywołując tę
funkcję w kodzie podasz jako argument tekst nie będący tekstową reprezentacją liczby, makro nie
uruchomi się, a kompilator wyświetli błąd Run-time error 13: Type mismatch.
Omawiając wywoływanie procedur z argumentami, zaznaczyłem, że wymagane argumenty
są tak jakby dodatkowymi zmiennymi w tej procedurze. Pod tym względem funkcje nie różnią się od procedur. Jeżeli
więc funkcja pensjaPoOpodatkowaniu
wymaga podania argumentu podstawa
, oznacza to, że zawiera
już co najmniej jedną zmienną - podstawa
.
W przypadku funkcji dodatkową zmienną jest też nazwa samej funkcji.
Jest to bardzo ważna zasada. Jeżeli nazwałeś funkcję pensjaPoOpodatkowaniu
jest to równoznaczne z tym,
jakbyś zadeklarował już w tej funkcji zmienną o takiej właśnie nazwie. Jeżeli spróbowałbyś dodać normalnym sposobem
zmienną o takiej samej nazwie (a więc wpisując Dim pensjaPoOpodatkowaniu
As Long
) spowodowałoby to wyświetlenie podczas próby uruchomienia makra
błędu Compile error: Duplicate declaration in current scope.
Musisz wiedzieć jeszcze jedną istotną rzecz na temat zmiennej, która jest równocześnie nazwą funkcji.
Otóż nie jest to zwykła zmienna, taka, jak wszystkie pozostałe. Jest to najważniejsza zmienna w całej
funkcji, która decyduje o tym, jaki będzie końcowy wynik działania funkcji.
Tak jak napisałem kilka akapitów wcześniej, funkcja jest jak skrzynka, która po wykonaniu przewidzianych
w niej operacji zwraca jeden wynik. Wynik ten jest zawsze równy wartości właśnie tej najważniejszej
zmiennej w momencie, kiedy funkcja kończy swoje działanie (a więc w momencie kiedy kod doszedł do
linijki End Function
).
W powyższym przykładzie funkcja zwróci więc taką wartość, jaka będzie przypisana do zmiennej o takiej samej
nazwie jak sama funkcja, czyli pensjaPoOpodatkowaniu
. Dlatego właśnie w drugim wierszu kodu
funkcji przypisano do tej zmiennej działanie obliczające wartość pensji po opodatkowaniu (działanie to
zostało już omówione w poprzedniej lekcji - od argumentu pensja
zostaje odjęte 18% jego wartości).
Kolejny wiersz jest już poleceniem zakończenia funkcji, a więc w tym momencie wartość zmiennej
pensjaPoOpodatkowaniu
zostaje oficjalnie końcowym wynikiem działania funkcji.
Jako, że funkcja zakończyła już swoje działanie, wykonywanie całego kodu wraca z powrotem do procedury
zarobki
, do wiersza 6, w którym tę procedurę opuściło, i przypisuje
do zmiennej pensjaNetto
wartość 2050, czyli wynik działania omówionej przed chwilą funkcji.
Funkcje mogą być też wywoływane za pomocą słowa kluczowego Call
tak, jakby były zwykłymi procedurami.
W takiej sytuacji funkcja oczywiście nie zwróci żadnej wartości, bo nie było by nawet do czego jej przypisać,
skoro wywoływana jest ona samoistnie.
Wywoływanie funkcji jak procedur ma sens tylko dla funkcji, które oprócz zwracania wartości wykonują jakieś inne
czynności, np. wyświetlają komunikaty czy zapisują plik. Przykład takiej funkcji poznasz już w jednej z kolejnych
lekcji, kiedy omawiane będzie wyświetlanie komunikatów dla użytkownika.
Wyjaśnienia wymaga jeszcze jedna kwestia, która może budzić wątpliwości.
Po co w ogóle w powyższym przykładzie użyta jest funkcja? Czy nie łatwiej byłoby to makro napisać po prostu tak:
1
2
3
4
5
6
7
8
Sub zarobki()
Dim pensjaBrutto As Long
Dim pensjaNetto As Long
pensjaBrutto = 2500
pensjaNetto = pensjaBrutto - (pensjaBrutto * 0.18)
End Sub
W powyższym fragmencie kodu wszystkie obliczenia jakie wykonywała funkcja pensjaPoOpodatkowaniu
zostały wstawione bezpośrednio do głównej procedury (zarobki
), która z tej funkcji korzystała.
Wydawać by się mogło, że takie rozwiązanie jest w tej sytuacji korzystniejsze, ponieważ skróciło długość całego kodu,
a i szybkość wykonywania całego makra powinna się zwiększyć, gdyż kompilator nie marnuje już czasu na wywoływanie
funkcji, przekazywanie do niej argumentów czy zwracanie wartości.
Faktycznie, w tak krótkim programie rozwiązanie takie jest do zaakceptowania. Jednak prawdziwe makra, które mają
jakieś poważne znaczenie użytkowe, są o wiele bardziej rozbudowane i składają się z setek procedur i funkcji.
Wyobraź sobie teraz, że Twoje rozbudowane makro składa się z 20 różnych procedur, z których każda musi w pewnym
momencie obliczyć pensję netto. Jeżeli nie zastosowałbyś funkcji i chciał wstawiać obliczenia bezpośrednio w kodzie
procedury, tak jak w przytoczonym przed momentem przykładzie, musiałbyś 20 razy powtórzyć ten sam fragment kodu.
W powyższej sytuacji obliczenia wykonywane przez funkcję mieszczą się w jednej linijce, więc perspektywa ich
20-krotnego powtórzenia nie jest może zbyt przerażająca. Jest to jednak tylko uproszczony model obliczania
podatku (z uwagi na to, że nie znasz jeszcze kilku ważnych operacji, na potrzeby tej lekcji założono, że
podatek w każdym przypadku wynosi 18%). W rzeczywistości chcąc wyliczyć podatek musiałbyś najpierw
sprawdzić do którego progu podatkowego należy pensja brutto, na tej podstawie wyznaczyć odpowiednią stawkę
i wyliczyć podatek. Takie obliczenia z pewnością zajmowałaby co najmniej kilka linijek.
W tym momencie wyraźnie zarysowuje się już więc przewaga funkcji.
Wykorzystując funkcję musiałbyś opisać te kilka linijek wyliczających podatek tylko w
jednym miejscu kodu, a każde późniejsze odniesienie do tej funkcji zajmowałoby już tylko jedną linijkę.
Gdybyś chciał się obejść bez funkcji i wstawiać obliczenia wyznaczające wysokość podatku bezpośrednio w procedurach,
musiałbyś za każdym razem od nowa wpisywać owe kilka linijek, co przy 20-krotnym powtórzeniu obliczenia byłoby
ogromnym marnotrawstwem czasu i miejsca.
Ale to jeszcze nie wszystkie argumenty przemawiające za korzystaniem z funkcji zamiast wstawiania
obliczeń bezpośrednio w procedurach.
Wyobraź sobie teraz dodatkowo, że rząd wprowadził zmiany w zasadach obliczaniu podatków, które musisz
uwzględnić w swojej aplikacji.
Jeżeli w swoim makrze korzystasz z funkcji obliczającej podatek, będziesz musiał dokonać tylko
jednej, jedynej modyfikacji - właśnie wewnątrz tej funkcji.
Gdybyś natomiast wstawiał obliczenia bezpośrednio w procedurach, musiałbyś się w takiej sytuacji podjąć
czasochłonnego zadania, jakim jest odszukanie każdego miejsca, w którym takie obliczenie występuje i dokonanie
na nim oddzielnej modyfikacji.
Jeżeli podejrzewasz, że jakieś obliczenia lub działania będziesz musiał wykorzystać więcej niż raz,
warto stworzyć na potrzeby tych obliczeń oddzielną funkcję.
Stwórz sobie oddzielny moduł, który będzie Twoją biblioteką użytecznych funkcji i od początku
swojej kariery programistycznej gromadź w nim wszystkie ważne funkcje, co do których masz podejrzenie,
że w przyszłości będą mogły się Tobie przydać w innym programie.
Rozpoczynając pracę nad nowym makrem rozpocznij od skopiowania do niego tego modułu-biblioteki, tak byś
nie musiał pisać od nowa uniwersalnych funkcji, kiedy zajdzie potrzeba skorzystania z nich.
Wykorzystanie własnych funkcji w arkuszu Excela
Wszystkie tworzone przez Ciebie funkcje mogą być wykorzystywane w tradycyjnym arkuszu Excelowym.
Skorzystanie z własnoręcznie napisanej funkcji jest bardzo proste i niczym nie różni się od korzystania z
fabrycznie wbudowanych funkcji dostępnych w Excelu (ponieważ one także są po prostu zwykłymi funkcjami,
tyle że napisanymi przez programistów Microsoftu).
Wystarczy więc, że w arkuszu wpiszesz znak równości, nazwę swojej funkcji i podasz niezbędne argumenty,
aby w danej komórce pojawił się wynik zwrócony przez tę funkcję.
Poniżej znajduje się przykład wykorzystania w arkuszu omówionej wcześniej funkcji pensjaPoOpodatkowaniu
.
REGUŁY KORZYSTANIA W ARKUSZU Z WŁASNYCH FUNKCJI
W arkuszu możesz korzystać ze wszystkich funkcji, które znajdują się w aktualnie otwartych plikach.
Funkcja pensjaPoOpodatkowaniu
może więc być użyta nie tylko w pliku, w którym została napisana,
ale także w każdym innym, o ile plik zawierający tę funkcję pozostaje otwarty.
Jeśli chcesz skorzystać w arkuszu z funkcji znajdującej się w innym pliku, musisz podać najpierw nazwę tego pliku,
wykrzyknik, a dopiero potem wpisać nazwę funkcji.
Wywołanie funkcji pensjaPoOpodatkowaniu
w pliku, który zawiera tę funkcję (test.xls):
=pensjaPoOpodatkowaniu(5000)
Wywołanie funkcji pensjaPoOpodatkowaniu
w każdym innym pliku:
=test.xls!pensjaPoOpodatkowaniu(5000)
Wyjątkiem są w tym przypadku funkcje zawarte w zainstalowanych dodatkach, które, mimo że znajdują się w innym
pliku, do wywołania potrzebują tylko podania swojej nazwy.
Tak naprawdę pliki dodatków (format *.xla, *.xlax) to jedyny słuszny sposób przechowywania własnych
funkcji przeznaczonych do wykorzystania w arkuszu.
Dodatek taki jest otwierany automatycznie wraz z otwarciem Excela (nie musisz się więc martwić o to, że
zapomnisz go otworzyć i w arkuszu zamiast obliczeń pojawią się błędy).
Ponadto, tak jak wspomniałem przed momentem, wywoływanie funkcji znajdujących się w dodatku nie wymaga
poprzedzania ich nazwy nazwą pliku, w którym są przechowywane (Więcej na temat tworzenia dodatków dowiesz
się w dalszej części kursu).
Jeżeli zamkniesz plik zawierający funkcję, z której korzystają inne pliki, to po odświeżeniu danych w Excelu
pojawią się błędy, takie jak na poniższym rysunku:
Zwróć też uwagę, że nazwa pliku, którą wpisano przed nazwą funkcji (test.xls!), automatycznie zamieniła
się w pełną ścieżkę dostępu do tego pliku.
Aby podejrzeć listę wszystkich dostępnych aktualnie funkcji użytkownika, musisz
otworzyć okno Wstawianie funkcji.
Możesz tego dokonać na dwa sposoby:
- wybrać z menu Excela polecenie
-
kliknąć przycisk rozwijania przy ikonie funkcji (na poniższym rysunku zaznaczona na czerwono) i wybrać
opcję Więcej funkcji... (zaznaczona na zielono).
Następnie w oknie Wstawianie funkcji wybierz kategorię Użytkownika (zaznaczona na rysunku na
czerwono), a na liście poniżej ujrzysz wszystkie funkcje znajdujące się w otwartych plikach.
W tym miejscu warto zwrócić uwagę na jedną kwestię. Otóż wspomniana lista funkcji zawiera zarówno funkcje,
którą są przeznaczone do użycia w arkuszu, jak i funkcje spełniające tylko jakieś role w makrach, które
absolutnie nie nadają się do wykorzystania w arkuszu, a ich wywołanie spowoduje jedynie wyświetlenie komunikatu
o błędzie.
Dla większej przejrzystości warto opracować sobie jakiś specjalny styl nazywania funkcji
przeznaczonych do wykorzystania w arkuszu, tak aby momentalnie można je było odróżnić od innych.
Przykładowo na powyższym rysunku nazwy wszystkich funkcji przeznaczonych do arkuszy zapisane są wielkimi
literami.
To wszystko jeżeli chodzi o podstawy działania funkcji. Oczywiście nie oznacza to, że temat funkcji nie będzie już więcej
poruszany. Wręcz przeciwnie, tak naprawdę to dopiero początek przygód z funkcjami, od teraz podczas każdej niemal lekcji
będziesz poznawał przykłady jakichś funkcji i wzbogacał swoją wiedzę na ich temat, dzięki czemu nabierzesz coraz większej
wprawy w ich stosowaniu.
Argumenty opcjonalne
W kilku poprzednich przykładach zapoznałeś się z procedurami i funkcjami, do których przekazywane były argumenty.
Jak wspomniano w lekcji piątej, jeżeli procedura lub funkcja wymaga podania argumentów,
to każda próba wywołania ich bez tych argumentów uniemożliwi uruchomienie makra i spowoduje wyświetlenie komunikatu o błędzie.
Zdarzają się jednak sytuacje, i to wcale nierzadko, kiedy funkcja lub procedura wymaga podania argumentu tylko w
niektórych sytuacjach, podczas gdy w innych argument ten nie jest konieczny.
Pozostańmy przy przykładzie funkcji obliczającej pensje netto i brutto.
Załóżmy teraz, że w niektórych przypadkach do wyliczenia pensji netto konieczne będzie jeszcze podanie dodatkowego czynnika
- na przykład wysokości kwoty wolnej od podatku. Równocześnie musi jednak pozostać dotychczasowa możliwość wyliczenia pensji
netto - bez informacji na temat kwoty wolnej od podatku, tylko na podstawie wysokości pensji brutto.
Zmodyfikuj funkcję pensjaPoOpodatkowaniu
tak, aby wyglądała jak poniżej (nowe elementy zostały wyróżnione na
czerwono):
1
2
3
4
5
6
7
Function pensjaPoOpodatkowaniu(podstawa As Long, _
Optional kwotaWolnaOdPodatku As Single) As Long
Dim kwotaDoOpodatkowania As Single
kwotaDoOpodatkowania = podstawa - kwotaWolnaOdPodatku
pensjaPoOpodatkowaniu = podstawa - (kwotaDoOpodatkowania * 0.18)
End Function
W powyższej wersji funkcji pensjaPoOpodatkowaniu
, w wierszu otwarcia funkcji pojawił się
nowy argument - kwotaWolnaOdPodatku
.
Tym, co odróżnia ten argument od wszystkich dotychczasowych, jest słowo Optional
znajdujące się przed
jego nazwą. Oznacza ono właśnie, że argument ten może być podany w wywołaniu funkcji, ale nie jest to konieczne i
funkcja równie dobrze zadziała w sytuacji, kiedy w wywołaniu zabraknie tego argumentu.
Poprawne są więc oba poniższe wywołania tej funkcji:
pensjaNetto = pensjaPoOpodatkowaniu(5000)
pensjaNetto = pensjaPoOpodatkowaniu(5000, 2542.24)
Do argumentu opcjonalnego można przypisać jakąś wartość domyślną, którą przyjmie ten argument w razie
pominięcia go przy wywoływaniu funkcji.
Wróćmy teraz do poprzedniej postaci funkcji pensjaPoOpodatkowaniu
(tej bez argumentu opcjonalnego) i
zmodyfikujmy ją tak, aby oprócz podstawy opodatkowania, umożliwiała podanie stopy podatkowej. Przyjmijmy jednak,
że stopa podatkowa zasadniczo wynosi 18%, a tylko w wyjątkowych sytuacjach będzie posiadała inną wartość i tylko
wtedy trzeba będzie ją podać jako argument przy wywoływaniu funkcji.
Funkcja powinna wówczas przyjąć następującą postać (nowe elementy zostały zaznaczone na czerwono):
1
2
3
4
5
Function pensjaPoOpodatkowaniu(podstawa As Long, _
Optional stopaPodatku As Single = 0.18) As Long
pensjaPoOpodatkowaniu = podstawa - (podstawa * stopaPodatku)
End Function
W powyższej wersji funkcji pensjaPoOpodatkowaniu
argumentem opcjonalnym jest argument
stopaPodatku
.
Po określeniu tego argumentu jako typ Single
dodatkowo podano jego wartość domyślną,
wynoszącą 0.18 (czyli 18%). Oznacza to, że we wszystkich sytuacjach, kiedy przy wywołaniu funkcji
nie określono argumentu stopaPodatku
, będzie on równy wartości domyślnej (czyli 18%).
Procedura lub funkcja może maksymalnie posiadać 60 argumentów wejściowych, przy czym stosunek argumentów obowiązkowych
do opcjonalnych może być zupełnie dowolny.
Jeżeli wymieniasz argumenty wejściowe danej funkcji, musisz zwrócić uwagę na to,
aby argumenty opcjonalne znajdowały się na samym końcu listy argumentów!
Niedopuszczalny jest na przykład taki zapis:
Function pensjaPoOpodatkowaniu(Optional
stopaPodatku As _
Single = 0.18, podstawa As Long)
ponieważ argument obowiązkowy występuje w nim po argumencie opcjonalnym.
Pamiętaj aby zawsze najpierw wymienić wszystkie argumenty obowiązkowe, a dopiero wtedy przejść do argumentów
opcjonalnych. Właściwie to nawet nie musisz o tym pamiętać, gdyż będzie o tym za Ciebie pamiętał edytor VBA.
Każdy wiersz otwarcia funkcji lub procedury, w którym argumenty opcjonalne pojawiają się przed obowiązkowymi
jest automatycznie podświetlany na czerwono i do czasu poprawienia go do prawidłowej postaci niemożliwe jest
uruchomienie makra.
Okno Immediate służy do wykonywania następujących czynności:
- sprawdzanie wartości i stanu zmiennych,
- uruchamianie procedur,
- szybkie sprawdzanie wyników funkcji.
Okno Immediate można uruchomić poprzez kliknięcie kombinacji klawiszy Ctrl + G,
a wygląda ono tak jak na poniższym rysunku (nie jest więc zbyt skomplikowane):
Sprawdzanie wartości zmiennych
Za pomocą okna Immediate można sprawdzać wartości zmiennych zarówno w momencie zatrzymania makra,
jak też bez przerywania jego działania.
Oba te sposoby zostaną zaprezentowane na przykładzie omówionego w tej lekcji makra do wyliczania pensji netto i brutto.
Ustaw punkt zatrzymania w wierszu zamknięcia (7)
procedury zarobki
, czyli w wierszu End Sub
, i uruchom makro.
Kiedy makro dojdzie do wiersza, w którym ustawiłeś punkt zatrzymania i wstrzyma swoje działanie, przejdź do okna
Immediate (możesz tego dokonać klikając w to okno myszką lub klikając kombinację klawiszy
Ctrl+G).
Gdy znajdziesz się już w oknie Immediate, wpisz znak zapytania oraz nazwę zmiennej, której wartość chcesz
podejrzeć, a potem wciśnij Enter, np:
Po wciśnięciu Entera edytor VBA wyświetli w wierszu poniżej Twojego zapytania jego wynik,
a kursor ustawi w następnym wierszu, tak byś mógł od razu wpisywać kolejne zapytania.
Być może ten sposób podpatrywania wartości zmiennych jest mniej wygodny i bardziej czasochłonny niż najeżdżanie kursorem
na nazwę zmiennej, omówione w poprzedniej lekcji, pozwala jednak sprawdzić o wiele większy zakres danych.
Za pomocą zapytania w oknie Immediate możesz sprawdzić mnóstwo rzeczy, także systemowych, z których kilka zostało
wymienionych w poniższej tabelce:
SPRAWDZANA WARTOŚĆ | ZAPYTANIE |
Nazwa aktywnego arkusza | ?ActiveSheet.Name |
Nazwa aktywnego pliku | ?ActiveWorkbook.Name |
Ścieżka do pliku | ?ThisWorkbook.Path |
Aktualny czas | ?Time |
Aktualna data | ?Date |
Aktualna data i czas | ?Now |
Nazwa zalogowanego użytkownika | ?Application.UserName |
Okno Immediate umożliwia również sprawdzanie wartości zmiennych w poszczególnych momentach działania
makra bez przerywania jego działania.
Przed zapoznaniem się z tym sposobem podpatrywania wartości zmiennych, wykasuj wszystko w oknie Immediate,
aby stare wpisy nie mieszały się z nowymi, które zaraz się pojawią.
Załóżmy teraz, że chcesz sprawić, aby procedura zarobki podczas swojego działania dwukrotnie wyświetlała informację
o wielkości zmiennej pensjaNetto
- najpierw przed przypisaniem do niej wyniku funkcji
pensjaPoOpodatkowaniu
, a potem po przypisaniu tej funkcji (za pierwszym razem powinna się więc wyświetlić
wartość 0, a za drugim 2050).
Zmodyfikuj procedurę zarobki
tak, aby wyglądała tak jak poniżej (nowe wiersze tradycyjnie zostały
wypisane czerwoną czcionką), a potem zdejmij z jej ostatniego wiersza punkt zatrzymania, który ustawiłeś testując
poprzedni przykład.
1
2
3
4
5
6
7
8
9
10
Sub zarobki()
Dim pensjaBrutto As Long
Dim pensjaNetto As Long
pensjaBrutto = 2500
Debug.Print pensjaNetto
pensjaNetto = pensjaPoOpodatkowaniu(pensjaBrutto)
Debug.Print pensjaNetto
End Sub
1
2
3
Function pensjaPoOpodatkowaniu(podstawa As Long) As Long
pensjaPoOpodatkowaniu = podstawa - (podstawa * 0.18)
End Function
Po uruchomieniu makra w oknie Immediate pojawią się następujące wpisy:
a więc dokładnie takie wyniki, jakie miały się w tym oknie pojawić.
Podsumowując - aby wyświetlić w oknie Immediate wartość jakiejś zmiennej podczas działania makra bez konieczności
jego zatrzymywania, musisz dodać następujący wpis w miejscu, w którym chcesz podejrzeć wartość zmiennej:
Debug.Print nazwaZmiennej
Jeżeli będziesz w czasie jednego uruchomienia makra wstawiał kilka takich Debug.Printów
,
możesz dodać do nich jakiś opis, abyś wiedział do której zmiennej odnosi się każdy z wpisów.
W powyższym przykładzie mógłbyś np. napisać w wierszu 6:
Debug.Print "Zmienna pensjaNetto przed przypisaniem funkcji: " & pensjaNetto
natomiast w wierszu 8:
Debug.Print "Zmienna pensjaNetto po przypisaniu funkcji: " & pensjaNetto
Wówczas po uruchomieniu makra, wyprintowane w oknie Immediate wyniki wyglądałyby następująco:
Uruchamianie makr
Za pomocą okna Immediate można też bardzo łatwo uruchamiać całe makra.
Wystarczy wpisać w nowym wierszu okna Immediate słowo kluczowe Call
oraz nazwę
procedury i wcisnąć Enter.
Jeżeli wpiszesz np. taki wiersz:
i wciśniesz Enter, edytor VBA uruchomi makro Zarobki
.
Sprawdzanie wyników funkcji
Ostatnią ważną rolą okna Immediate jest szybkie sprawdzanie wyników funkcji.
Jeżeli chcesz na przykład szybko sprawdzić wynik funkcji pensjaPoOpodatkowaniu
z poprzedniego
przykładu dla pensji brutto wynoszącej 5000, wystarczy, że wpiszesz w oknie Immediate następujące
polecenie:
?pensjaPoOpodatkowaniu(5000)
i wciśniesz Enter, a pod spodem pojawi się wynik 4100.
W ten sposób możesz szybko sprawdzać wyniki funkcji oraz testować nowe funkcje, zadając kilka takich
zapytań i sprawdzając czy zwracają oczekiwane przez Ciebie rezultaty.
Przy wpisywaniu poleceń w oknie Immediate możesz korzystać z
autopodpowiedzi.
Po wpisaniu dwóch pierwszych liter nazwy funkcji pensjaPoOpodatkowaniu
wciśnij
Ctrl+Spacja, a nazwa automatycznie wpisze
się sama (ponieważ nie ma żadnej innej funkcji ani procedury rozpoczynające się literami pe).
Pamiętaj o autouzupełnianiu i korzystaj z niego cały czas, zarówno w normalnym edytorze VBA jak i w oknie
Immediate. Znacznie zwiększy to efektywność Twojej pracy.