08 - Komunikacja z użytkownikiem


W tej lekcji poznamy podstawowe sposoby komunikacji z użytkownikiem. Dowiemy się jak wyświetlać komunikaty do osób korzystających z Twoich makr, jak wyświetlać okienka z zapytaniam (np. potwierdzenie usunięcia jakichś danych) oraz jak sprawić, aby w trakcie działania makra użytkownicy mogli podać jakieś informacje, które będą potem w tym makrze wykorzystane.

Zanim jednak zostaną omówione sposoby komunikacji z użytkownikiem, poznamy jeszcze kilka interesujących informacji na temat wywoływania funkcji i procedur, które będą przydatne także podczas omawiania tematu przewodniego tej lekcji.

Kolejność argumentów w wywoływaniu procedur i funkcji

Wiesz już doskonale, że wywołując jakąś procedurę czy funkcję, można do niej przekazać jakieś argumenty. W lekcji poświęconej funkcjom dowiedziałeś się również, że część z tych argumentów (a nawet wszystkie) może być opcjonalna. Wspomniałem również, że funkcja lub procedura maksymalnie mogą liczyć 60 argumentów.

Spójrz teraz na poniższy fragment kodu:
1
2
3
4
5
6
7
8
9
10
Function pensjaPoOpodatkowaniu(podstawa As Long, _
    Optional stawka As Single = 0.18, _
    Optional ulgaProrodzinna As Single, _
    Optional ulgaNaInternet As Single, _
    Optional ulgaMieszkaniowa As Single, _
    Optional ulgaBudowlana As Single) As Long

    pensjaPoOpodatkowaniu = podstawa - (podstawa - ulgaProrodzinna - _
       ulgaNaInternet - ulgaMieszkaniowa - ulgaBudowlana) * stawka
End Function

Jest to omawiana już kilkakrotnie funkcja do obliczania pensji netto. Jednak na potrzeby dyskutowanego teraz zagadnienia jej konstrukcja została trochę skomplikowana, ponieważ oprócz wymaganego już wcześniej argumentu podstawa, pojawiło się też 5 nowych argumentów opcjonalnych. Wszystko po to, aby zaprezentować Tobie przykład rozbudowanej funkcji, posiadającej wiele argumentów, zwłaszcza opcjonalnych (zanim wkleisz ją do swojego edytora, upewnij się, że usunąłeś poprzednią wersję tej funkcji - w jednym module nie mogą znajdować się dwie funkcje o takiej samej nazwie!).

Jak wiesz, argumenty opcjonalne mają to do siebie, że mogą, ale nie muszą być podane przy wywoływaniu funkcji.

Wyobraź sobie sytuację, w której chcesz skorzystać z powyższej wersji funkcji pensjaPoOpodatkowaniu, a jedynym argumentem opcjonalnym, który chcesz podać jest ostatni z nich - ulgaBudowlana (oczywiście będziesz musiał też podać argument podstawa, który jest w tej funkcji wymagany).

Poniżej opisano dwa sposoby na ominięcie pozostałych opcjonalnych argumentów i podanie tylko ostatniego z nich (testując je operuj na oknie Immediate).

Poniższy wiersz z okna Immediate przedstawia pierwszy z tych sposobów:
 
?pensjaPoOpodatkowaniu(5000, , , , , 1000)

W tym przykładzie funkcja pensjaPoOpodatkowaniu została wywołana z argumentem podstawa równym 5000 oraz argumentem ulgaBudowlana równym 1000.

Jak widzisz, w miejscu argumentów opcjonalnych, których nie chcesz podawać przy wywołaniu funkcji lub procedury, trzeba po prostu wstawić spację i przecinkiem przejść do kolejnego argumentu (przecinek to znak informujący kompilator o przejściu do określania kolejnego argumentu z listy argumentów danej funkcji lub procedury).


Taki sposób ma oczywiście swoje zalety i wady.

Zaletą jest na pewno szybkość, ponieważ w miejsce omijanych argumentów opcjonalnych wstawia się jedynie spację i przechodzi do kolejnego argumentu.

Główną wadą takiego rozwiązania jest natomiast jego nieczytelność. Patrząc na powyższą linijkę kodu, na pierwszy rzut oka nie masz pojęcia którego argumentu dotyczy liczba 1000. W przytaczanym przykładzie można się jeszcze w miarę łatwo domyślić, do którego argumentu przypisana jest wartość 1000, ponieważ jest to ostatni argument z listy. Zdarzają się jednak sytuacje, że funkcja posiada przykładowo 20 argumentów opcjonalnych, a podany ma być tylko dwunasty z nich.

W przypadku funkcji z bardzo dużą liczbą argumentów opcjonalnych, z których większość ma być pominięta, ujawnia się też druga wada tej metody - konieczność niepotrzebnego wpisywania wielu spacji z przecinkiem. Oprócz tego, że jest to zajęcie czasochłonne i bardzo nieczytelnie wygląda w kodzie, mogłoby też prowadzić do wielu pomyłek, gdyż wpisując te spacje łatwo się pomylić i zapomnieć przy którym argumencie aktualnie się znajduje. Ale w tej kwestii z pomocą przychodzi edytor VBA i jego narzędzie Auto Quick Info, które przy podawaniu argumentów procedury i funkcji podświetla argument, który jest w danym momencie wpisywany (tak jak pokazano na poniższym obrazku).

Podświetlanie aktualnie podawanego argumentu

Drugi sposób omijania niepotrzebnych argumentów opcjonalnych w przypadku funkcji o małej liczbie argumentów wymaga nieco więcej pisania niż poprzedni, jest za to o wiele bardziej czytelny. Natomiast dla funkcji z bardzo dużą liczbą argumentów opcjonalnych, spośród których tylko nieliczne mają zostać określone, nawet ta wada przestaje mieć znaczenie i sposób ten staje się jedynym słusznym wyborem.

Sposób ten został przedstawiony w poniższym wierszu kodu:
 
?pensjaPoOpodatkowaniu(podstawa:=5000, ulgaBudowlana:=1000)

Za pomocą tej metody należy określić nazwę każdego z podawanych argumentów, wstawić dwukropek ze znakiem równości (:=) i przypisać do niej wartość.

Stosując to rozwiązanie po prostu ignorujesz wszystkie niepotrzebne w danym wywołaniu argumenty wywoływanej funkcji.

Drugi z opisanych sposobów jest zarazem jedyną metoda na podanie argumentów w innej kolejności niż zostało to określone przy tworzeniu funkcji.

Powyższa funkcja równie dobrze zadziałałaby, gdyby została wywołana w taki sposób:
 
?pensjaPoOpodatkowaniu(ulgaBudowlana:=1000, podstawa:=5000)

Zagnieżdżanie funkcji

Podobnie jak w tradycyjnym arkuszu Excelowym, programując w VBA możesz stosować zagnieżdżanie funkcji. Oznacza to, że jako argument funkcji lub procedury możesz podać inną funkcję.

Bez żadnych problemów zadziała na przykład poniższy wpis, w którym jako argument funkcji pensjaPoOpodatkowaniu podana została funkcja Abs(-5000).
 
?pensjaPoOpodatkowaniu(Abs(-5000))

Obliczając takie wyrażenie, kompilator rozpoczyna od obliczenia funkcji znajdującej się na najniższym poziomie hierarchii, czyli w tym przypadku od funkcji Abs(-5000).

Gdyby jako argument funkcji Abs również podana była jakaś funkcja, to właśnie od niej rozpoczęłoby się obliczanie całego wyrażenia.

Zagnieżdżając funkcje musisz zwracać uwagę na wymagane typy argumentów i typy zwracane przez zagnieżdżane funkcje. Aby lepiej zrozumieć tę zasadę, wykonaj przedstawiony poniżej eksperyment.

Wklej do edytora poniższą funkcję:
1
2
3
Function zwrocTekst() As String
    zwrocTekst = 5000
End Function

Funkcja ta nie wymaga podania żadnego argumentu i za każdym razem zwraca wartość 5000. Zwracana wartość jest tekstem ponieważ w wierszu otwarcia określono za pomocą słów kluczowych As String, że funkcja zwraca wartości tekstowe.

Spróbuj teraz uruchomić w oknie Immediate następujący wiersz:
 
?pensjaPoOpodatkowaniu("5000")

Jak widzisz, funkcja zadziałała idealnie, mimo że podałeś jako argument wartość tekstową 5000, podczas gdy argument podstawa wymagał argumentu typu Long. Kompilator bez kłopotu przetłumaczył sobie tekst 5000 (czyli identyczny tekst, jaki zwraca funkcja zwrocTekst) na liczbę o takiej samej wartości.

Teraz spróbuj uruchomić w oknie Immediate tę samą funkcję, ale zamiast tekstu 5000 podaj w argumencie funkcję zwrocTekst. Jak pamiętasz, funkcja ta zawsze zwraca w swoim wyniku tekst 5000 (czyli ten sam, który przed momentem idealnie zadziałał), więc teoretycznie również nie powinno być problemu z jej uruchomieniem.

 
?pensjaPoOpodatkowaniu(zwrocTekst)

Tak się jednak nie stało. Edytor VBA w ogóle nie uruchomił funkcji, a zamiast tego wyświetlił komunikat o błędzie Run-time error '13': Type mismatch.

Wniosek z tego eksperymentu jest prosty: Funkcja zagnieżdżana w innej funkcji, musi zwracać typ danych identyczny z typem reprezentowanym przez argument, w miejsce którego ta funkcja jest wstawiana.

Istnieje pewien sposób na ominięcie tego ograniczenia, który wymaga zastosowania omówionych w poprzedniej lekcji funkcji konwersji.

Jeżeli zamiast argumentu typu Long chcesz podać funkcję, która zwraca typ String, musisz dodatkowo przerobić tę funkcję funkcją konwertującą do odpowiedniego typu danych, w tym przypadku funkcją CLng. W poniższej linijce kodu zmodyfikowano wcześniejsze zapytanie, tak aby zadziałało bez generowania błędów:
 
?pensjaPoOpodatkowaniu(CLng(zwrocTekst))

W tym kodzie zagnieżdżone są dwie funkcje: zwrocTekst oraz CLng. Jak już wcześniej wspomniałem, kompilator kodu rozpoczyna wykonywanie obliczeń od najbardziej wewnętrznych funkcji, w tym przypadku od funkcji zwrocTekst, która zwraca wartość tekstową 5000. Następnie przechodzi do kolejnej funkcji CLng, która ma teraz za zadanie przekonwertować otrzymaną z funkcji zwrocTekst wartość tekstową 5000 do liczby o takiej samej wartości. Kiedy funkcja CLng skończy swoje działanie przekazuje 5000, już w postaci liczbowej, do głównej funkcji tego zapytania - pensjaPoOpodatkowaniu.

W Excelu 2003 zagnieżdżanie funkcji jest ograniczone do maksymalnie siedmiu poziomów. Takiego ograniczenia nie ma w języku VBA, ale w rzeczywistości nie powinno się stosować więcej niż 4-5 poziomów zagnieżdżania, ponieważ po przekroczeniu tej liczby kod staje się bardzo nieczytelny i podatny na błędy.

Wyświetlanie komunikatów

Wyświetlanie komunikatów dla użytkownika to bardzo ważny element programowania. Za pomocą okienek z odpowiednim komunikatem można przekazać użytkownikowi szereg istotnych informacji, takich jak np. brak niezbędnych danych, błędy występujące podczas działania aplikacji czy też informację o pomyślnym zakończeniu działania makra.

Poniżej znajduje się proste makro, którego jedynym zadaniem jest wyświetlenie powitania. Oczywiście nie ma ono zbyt dużej wartości użytkowej, ale w prosty sposób pokaże Ci jak wstawiać w kodzie VBA komunikaty.

Najpierw wklej do swojego edytora VBA poniższy kod i uruchom makro, aby zobaczyć jak działa, a następnie przejdź do analizy kodu, znajdującej się pod ramką.

1
2
3
4
Sub wyswietlaniePowitania()
    Call MsgBox("Witaj! To jest makro prezentujące " & _
        "wyświetlanie komunikatów dla użytkownika.")
End Sub

Jedyną czynnością, jaką wykonuje powyższe makro jest wyświetlenie na ekranie ramki takiej, jak na poniższym obrazku:

Wyświetlanie komunikatu

Pomijając wiersz otwarcia i zamknięcia, które powinieneś już doskonale znać, procedura składa się tylko z jednego polecenia: MsgBox.

MsgBox to wbudowana funkcja VBA, która odpowiada za wyświetlanie komunikatów do użytkownika i odczytywanie jego reakcji na te komunikaty.

Jeżeli podczas działania makra kompilator natrafi na funkcję MsgBox i wyświetli na ekranie okno komunikatu, to wykonywanie kolejnych instrukcji znajdujących się po tej funkcji jest wstrzymane do momentu, kiedy okno komunikatu zostanie zamknięte.

Składnia funkcji MsgBox przedstawia się następująco:

1
2
3
Function MsgBox(Prompt As String, _
    Optional Buttons As VbMsgBoxStyle = vbOKOnly, Optional Title As _
    String, Optional HelpFile, Optional Context) As VbMsgBoxResult

Poniżej zostały opisane trzy podstawowe argumenty funkcji MsgBox - Prompt, Buttons oraz Title.

Prompt

Argument Prompt to jedyny wymagany argument funkcji MsgBox. Jest to argument typu tekstowego i odpowiada za tekst, który pojawi się w okienku wyświetlonym na ekranie użytkownika.

W przytoczonym przykładzie argument Prompt miał wartość Witaj! To jest makro prezentujące wyświetlanie komunikatów dla użytkownika i taka też wartość pojawiła się jako komunikat.

Wyświetlając komunikaty za pomocą funkcji MsgBox, nie musisz ograniczać się do wypisywania ich jednym ciągiem. Język VBA posiada specjalne polecenia, które umożliwiają przeniesienie części komunikatu do nowej linijki lub zastosowanie wewnątrz komunikatu tabulatorów.

Poniżej znajduje się zmodyfikowana procedura wyswietlaniePowitania, w której dodano aktualną datę i czas (zastosowane tutaj funkcje zwracające aktualną datę i czas zostały omówione w poprzedniej lekcji) i przeniesiono je do nowej linijki (nowe fragmenty kodu zostały oznaczone na czerwono).
1
2
3
4
5
6
7
Sub wyswietlaniePowitania()
    Call MsgBox("Witaj!" & vbCrlf & "Oto makro prezentujące " & _
        "wyświetlanie komunikatów dla użytkownika." & _
        vbCrLf & vbCrLf & vbCrLf & _
        "Aktualna data: " & Date & vbCrLf & _
        "Aktualny czas: " & Time)

End Sub

Jak widać w kodzie umieszczonym powyżej, aby przenieść część komunikatu do następnej linijki, należy zamknąć cudzysłowem dotychczasowy tekst komunikatu, dopisać znak łączenia znaków otoczony spacjami ( & ), potem wpisać słowo kluczowe vbCrLf, ponownie wstawić znak łączenia znaków ze spacjami z lewej i prawej strony ( & ) i kontynuować pisanie komunikatu dla użytkownika. Część znajdująca się po słowie kluczowym vbCrLf znajdzie się w komunikacie już w nowym wierszu.

Pomiędzy częścią Oto makro prezentujące wyświetlanie komunikatów dla użytkownika., a wyświetlaniem aktualnej daty, słowo kluczowe vbCrLf zostało wstawione trzykrotnie, dzięki czemu w komunikacie pojawią się dodatkowo dwie puste linijki, które wyraźnie oddzielą obie części komunikatu.

Wyświetlony komunikat powinien wyglądać tak jak na poniższym rysunku:

Przenoszenie części komunikatu do nowego wiersza

Oprócz przenoszenia części komunikatu do nowego wiersza, VBA umożliwia również wstawianie w komunikatach tabulatorów, które przesuwają tekst o kilka znaków w prawo w ramach tej samej linijki.

Poniższy kod jest modyfikacją poprzedniego, w którym, oprócz przeniesienia niektórych fragmentów komunikatu do nowych linijek, nagłówki Aktualna data: i Aktualny czas: oddzielono kilkoma tabulatorami od ich wartości (tradycyjnie nowe fragmenty kodu zostały podświetlone na czerwono).
1
2
3
4
5
6
7
Sub wyswietlaniePowitania()
    Call MsgBox("Witaj!" & vbCrLf & "Oto makro prezentujące " & _
        "wyświetlanie komunikatów dla użytkownika." & _
        vbCrLf & vbCrLf & vbCrLf & _
        "Aktualna data: " & vbTab & vbTab & Date & vbCrLf & _
        "Aktualny czas: " & vbTab & vbTab & Time)
End Sub

Zmodyfikowana funkcja wyświetli komunikat taki jak na poniższym rysunku:

Komunikat z tabulatorami

Aby w komunikacie oddzielić od siebie dwie części tekstu tabulatorem, należy zamknąć pierwszą część tekstu cudzysłowem, wstawić polecenie & vbTab & , a potem wpisać drugą część komunikatu, która pojawi się już przesunięta względem pierwszej części tekstu o określoną liczbę tabulatorów.

Polecenia vbCrLf i vbTab mają zastosowanie nie tylko przy wyświetlaniu komunikatów za pomocą funkcji MsgBox, ale wszędzie tam, gdzie masz do czynienia z tekstami - mogą być one elementem każdej zmiennej tekstowej.

Jeżeli w makrze pojawiłaby się przykładowo taka linijka kodu:
 
Cells(1,1) = "pierwszy wiersz" & vbCrLf & "drugi wiersz"
to w komórce A1, tekst ten zostałby zapisany tak jak na poniższym rysunku, o czym zresztą łatwo możesz się przekonać na własne oczy, wklejając i wywołując tę linijkę w oknie Immediate.

Rozbicie tekstu w komórce arkusza

Buttons

Argument Buttons, jak sama nazwa wskazuje, jest odpowiedzialny za wygląd przycisków i ikon, jakie pojawią się w oknie z komunikatem dla użytkownika.

Poniższa lista przedstawia podstawowe parametry, jakie można określić za pomocą argumentu Buttons:
  • liczba przycisków w oknie z komunikatem,
  • domyślnie wybrany przycisk,
  • ikona, która towarzyszy komunikatowi,
  • wyrównanie tekstu w oknie komunikatu.

Przy określaniu każdego z powyższych parametrów masz do wyboru pewną liczbę wariantów, które zostaną opisane poniżej. Nie ma konieczności określania każdego parametru - możesz opisać tylko niektóre z nich, dla pozostałych zostaną wówczas przypisane wartości domyślne.

Jeżeli argument Buttons jest całkowicie pominięty, dla wszystkich parametrów zostaną przypisane wartości domyślne - a więc w oknie komunikatu pojawi się tylko przycisk OK, który jako jedyny przycisk będzie oczywiście domyślnie zaznaczony, a tekst komunikatu będzie wyrównany do lewej i nie będzie mu towarzyszyła żadna ikona.

Określanie kolejnych parametrów wygląda w kodzie tak, jakby były one do siebie dodawane - oznacza to, że należy wybrać z listy wartość dla pierwszego parametru, następnie wstawić znak plusa, wybrać wartość dla kolejnego parametru itd. Po szczegółowym opisie wszystkich parametrów znajdziesz kilka przykładów prezentujących sposób określania parametrów przykładach.

Pierwszym parametrem opisywanym przez argument Buttons jest liczba oraz nazwy przycisków, jakie pojawią się w oknie komunikatu.

Jeżeli parametr ten zostanie pominięty, domyślnie wyświetlony zostanie tylko jeden przycisk z napisem OK.

Dostępne zestawy parametrów zostały zaprezentowane w poniższej tabelce (zapamiętaj, że wartości przedstawione w lewej kolumnie tabeli muszą być wpisywane w kodzie bez cudzysłowów, ponieważ nie są one zmiennymi tekstowymi lecz tzw. wartościami wyliczeniowymi, które będą omówione w późniejszej części kursu):

Liczba i nazwy przycisków w oknie komunikatu

WARTOŚĆWYŚWIETLANE PRZYCISKI
vbOKOnlywyświetla tylko przycisk OK
vbOKCancelwyświetla przyciski OK oraz Cancel
vbAbortRetryIgnorewyświetla przyciski Abort, Retry oraz Ignore
vbYesNoCancelwyświetla przyciski Yes, No oraz Cancel
vbYesNowyświetla przyciski Yes oraz No
vbRetryCancelwyświetla przyciski Retry oraz Cancel

Nazwy pojawiające się na przyciskach są uzależnione od zainstalowanego systemu operacyjnego. Niestety nie da się zmodyfikować funkcji MsgBox tak, aby dostosować nazwy przycisków do własnych potrzeb. W późniejszej części kursu nauczysz się jednak tworzyć własne, bardziej zaawansowane narzędzia do interakcji z użytkownikiem, gdzie w razie potrzeby, będziesz mógł wstawiać własne nazwy przycisków.

Stosowanie różnych zestawów przycisków służy oczywiście temu, aby makro wywoływało odpowiednie czynności w zależności od tego, który z tych przycisków został wciśnięty.

Przykłady wywoływania czynności na podstawie wciśniętego przycisku zostaną jednak omówione dopiero w następnej lekcji, kiedy poznasz konstrukcję warunkową If ... Then, niezbędną do konstruowania tego typu poleceń.

Na razie zapamiętaj tylko, że w oknie komunikatu mogą pojawiać się różne zestawy przycisków. Nie ma sensu uczyć się ich na pamięć, ponieważ po pierwsze zawsze możesz zajrzeć do przedstawionej powyżej tabelki, a po drugie przy pisaniu kodu edytor VBA pokazuje listę dostępnych wartości (tak jak to przedstawiono na poniższym obrazku), dzięki czemu, nie dość że nie będziesz musiał pamiętać ich dokładnych nazw, to jeszcze zaoszczędzisz sporo czasu, gdyż zamiast wpisywać je ręcznie, będziesz mógł wybrać je z listy.

Autouzupełnianie przy wpisywaniu argumentu Buttons

W tej konkretnej sytuacji autouzupełnianie ma jednak pewną wadę - wartości dla wszystkich parametrów znajdują się na jednej liście i są ze sobą wymieszane, w związku z czym początkowo możesz mieć niewielkie trudności przy ich wyborze. Na szczęście jednak wartości są dosyć dobrze nazwane i nawet nie mając ich biegle opanowanych, bez trudu domyślisz się, czego dotyczą poszczególne z nich (w ostateczności zawsze możesz zajrzeć do spisu wartości przy każdym parametrze omówionym w tej lekcji).

Jeżeli w oknie komunikatu umieściłeś zestaw przycisków zawierający przycisk Cancel to wciśnięcie krzyżyka służącego do zamykania okna umieszczonego w jego prawym górnym rogu lub klawisza Esc będzie równoznaczne z wciśnięciem przycisku Cancel.

Jeżeli Twoje okno nie zawiera przycisku Cancel to rolę tę przejmuje przycisk OK.

Jeżeli okno nie zawiera żadnego z tych dwóch przycisków, wciśnięcie klawisza Esc przy wyświetlonym oknie komunikatu nie odniesie żadnych skutków. Niemożliwe jest też w takiej sytuacji zamknięcie okna komunikatu poprzez wciśnięcie krzyżyka w prawym górnym rogu. Jedynym sposobem zamknięcia okna jest wówczas kliknięcie któregoś z dostępnych przycisków.

Drugim z parametrów określanych poprzez argument Buttons jest przycisk, który ma być domyślnie zaznaczony przy wyświetlaniu okna z komunikatem.

Wartości określające domyślny przycisk są tak proste, że w zasadzie nie ma sensu ich wyjaśniania, ale dla spójności całej lekcji zostały przedstawione w poniższej tabelce.

Wartości określające domyślnie wybrany przycisk

WARTOŚĆDOMYŚLNY PRZYCISK
vbDefaultButton1domyślnie wybrany pierwszy przycisk
vbDefaultButton2domyślnie wybrany drugi przycisk
vbDefaultButton3domyślnie wybrany trzeci przycisk
vbDefaultButton4domyślnie wybrany czwarty przycisk

Podobnie jak w przypadku wartości określających liczbę przycisków i pozostałe parametry, poniższe wartości muszą być wpisywane w edytorze bez cudzysłowów, ponieważ nie są tekstami, lecz wartościami wyliczeniowymi.

Jeżeli liczba przycisków będzie mniejsza niż numer domyślnego przycisku (np. okno będzie posiadało tylko przyciski OK i Cancel, a równocześnie zostanie określone, że domyślnym przyciskiem jest przycisk trzeci) automatycznie domyślnym przyciskiem zostanie uczyniony pierwszy przycisk.

Kolejnym parametrem, który można określić za pomocą argumentu Buttons jest ikona pojawiająca się obok tekstu komunikatu.

Wraz z wybraną ikoną, przy wyświetlaniu okna komunikatu generowany jest też sygnał dźwiękowy systemowo przypisany do danego zdarzenia.

Poniższa tabela zawiera dostępne wartości oraz rysunki odpowiadających im ikon.

Wartości określające ikonę w oknie komunikatu

WARTOŚĆIKONA
vbCritical

vbCritical

vbExclamation

vbExclamation

vbInformation

vbInformation

vbQuestion

vbQuestion

Jeżeli parametr ten nie zostanie określony, domyślnie obok tekstu komunikatu nie pojawi się żadna ikona.

Wreszcie ostatnim parametrem definiowanym przez argument Buttons jest wyrównanie tekstu komunikatu.

Tutaj do wyboru jest tylko jedna wartość - vbMsgBoxRight, oznaczająca, że tekst będzie wyrównywany do prawej strony.

Aby wyrównać tekst do lewej strony wystarczy pominąć ten parametr, ponieważ wyrównanie do lewej jest jego domyślnym ustawieniem.

Pamiętaj, aby do każdego parametru wybrać tylko jedną wartość. Równoczesne określenie kilku wartości dla tego samego parametru może prowadzić do nieprzewidzianych rezultatów!

Title

Argument opcjonalny Title pozwala zmienić napis wyświetlany na niebieskim pasku u góry okna komunikatu.

Domyślnie na pasku tym pojawia się napis Microsoft Excel. Taki też napis pojawił się we wszystkich wcześniejszych wywołaniach okna komunikatu, przedstawionych w niniejszej lekcji, ponieważ za każdym razem argument Title był pomijany.

Warto poświęcić trochę czasu i zadbać o to, aby okna z komunikatami były dobrze zatytułowane, co zawsze dodaje aplikacji profesjonalizmu.

Poniżej przedstawiono kod makra wyświetlającego komunikat powitalny (z początku tego podrozdziału), wzbogacony o tytuł okna komunikatu.

1
2
3
4
5
Sub wyswietlaniePowitania()
    Call MsgBox(Prompt:="Witaj! To jest makro prezentujące " & _
        "wyświetlanie komunikatów dla użytkownika.", _
        Title:="Powitanie")
End Sub

Okno wyświetlane przez ten zmodyfikowany kod wygląda tak jak na poniższym obrazku. Zwróć uwagę na tytuł na niebieskim pasku u góry okna.

Powitanie z tytułem

Przykłady wywołań okna komunikatu

Poniżej przedstawiono kilka przykładów wywołań okna komunikatu. Każdy z przykładów składa się z odpowiedniego fragmentu kodu oraz obrazka pokazującego wyświetlone okno.

Okno komunikatu z dwoma przyciskami: OK i Cancel (gdzie przycisk Cancel jest domyślny) oraz ikoną stanu krytycznego.

1
2
3
4
Sub wyswietlaniePowitania()
    Call MsgBox("Tekst komunikatu", _
        vbOKCancel + vbCritical + vbDefaultButton2, "Tytuł okna")
End Sub

Okno z dwoma przyciskami i ikoną stanu krytycznego

Okno komunikatu z trzema przyciskami: Yes, No oraz Cancel (gdzie przycisk Cancel jest domyślny) oraz ikoną zapytania.

1
2
3
4
5
Sub wyswietlaniePowitania()
    Call MsgBox("Czy na pewno chcesz usunąć plik?", _
        vbYesNoCancel + vbQuestion + vbDefaultButton3, _
        "Potwierdzenie usunięcia")
End Sub

Okno z trzema przyciskami i ikoną zapytania

Okno komunikatu z dwoma przyciskami: OK i Cancel oraz ikoną ostrzeżenia, w którym treść komunikatu wyrównana jest do prawej.

1
2
3
4
Sub wyswietlaniePowitania()
    Call MsgBox("Wyrównanie do prawej", _
        vbOKCancel + vbExclamation + vbMsgBoxRight, "Ostrzeżenie")
End Sub

Okno z dwoma przyciskami i ikoną ostrzeżenia

Pobieranie wartości od użytkownika

Obok omówionej funkcji MsgBox, wyświetlającej komunikaty i umożliwiającej użytkownikom podejmowanie prostych decyzji (Tak/Nie, Zatwierdź/Anuluj), język VBA udostępnia jeszcze drugą funkcję służącą do komunikacji z użytkownikami - InputBox.

Zadaniem funkcji InputBox jest pobieranie od użytkowników bardziej złożonych informacji, takich jak np. haseł, nazw, dat lub wartości liczbowych.

Skopiuj poniższy kod i wklej go do edytora:
1
2
3
4
5
6
Sub pobieranieWartosci()
    Dim tekst As String
   
    tekst = InputBox("Wartość, która pojawi się w komórce A1")
    Cells(1,1) = tekst
End Sub

Działanie całego makra polega na wyświetleniu okienka identycznego, jak na poniższym obrazku

Okno InputBox

a następnie pobranie wartości, którą użytkownik wpisał w tym oknie, i wpisanie jej do komórki A1 aktywnego arkusza.

W drugiej linijce kodu zostaje zadeklarowana zmienna typu tekstowego tekst.

W czwartym wierszu do zmiennej tekst zostaje przypisany wynik działania funkcji InputBox, czyli wartość wpisana w przedstawionym przed momentem oknie (sposób działania funkcji InputBox za chwilę zostanie szczegółowo omówiony).

Wreszcie w ostatnim wierszu procedury przed jej zamknięciem (5), znajduje się znane Ci już polecenie Cells(1,1) = tekst, które w komórce A1 aktywnego arkusza wyświetla wartość zmiennej tekst.

W powyższej procedurze zmienna tekst mogłaby zostać pominięta, a wynik funkcji od razu zapisany w arkuszu za pomocą poniższego wiersza:
 
Cells(1,1) = InputBox("Wartość, która pojawi się w komórce A1")

Korzystanie ze zmiennych pośredniczących w takich przykładach, jak powyżej, wydłuża wprawdzie cały kod, ale ma na celu przyzwyczaić Cię do deklarowania zmiennych, co przy większych i bardziej skomplikowanych makrach, którymi będziesz się zajmował w przyszłości, okaże się bardzo przydatne.

Szczegółowego omówienia wymaga wiersz 4 tej procedury, w którym pojawił się jedyny nowy element - bohaterka niniejszego podrozdziału, funkcja InputBox.

Postać ogólna funkcji InputBox przedstawia się następująco:
 
 
 
 
Function InputBox(Prompt As String, _
    Optional Title As String, Optional Default, _
    Optional XPos As Single, Optional YPos As Single, _
    Optional HelpFile, Optional Context) As String

Argumenty Prompt oraz Title zostały już szczegółowo omówione przy okazji podrozdziału poświęconego funkcji MsgBox. W funkcji InputBox ich działanie jest identyczne: argument Prompt odpowiada więc za treść komunikatu dla użytkownika (w tym przypadku będzie to instrukcja dotycząca pobieranej wartości, np.: Wpisz datę urodzenia lub Wpisz hasło), natomiast wartość argumentu Title pojawi się na górnym pasku okna wyświetlanego na ekranie.

Oba elementy zostały zaznaczone na poniższym rysunku (czerwoną ramką oznaczono miejsce, gdzie w oknie InputBox pojawia się wartość argumentu Prompt, natomiast zieloną - miejsce, w którym wyświetlony jest tekst podany jako argument Title).

Elementy okna InputBox

Argument Default pozwala zdefiniować wartość domyślną, jaka ma się pojawić w polu tekstowym wyświetlanego okna. Argument ten może przyjmować wartości wszystkich typów podstawowych.

Jeżeli argument Default zostanie pominięty, okno InputBox będzie wyświetlone z pustym polem tekstowym.

Argumenty XPos i YPos odpowiadają za początkową pozycję okna InputBox na ekranie (po jego wyświetleniu możesz je przesunąć w dowolne miejsce ekranu).

Argument XPos określa odległość okna InputBox od lewej krawędzi ekranu, natomiast argument YPos jego odległość od górnej krawędzi.

Obie te wartości wyrażane są w jednostkach zwanych twipsami (1440 twipsów = 1 cal).

W sytuacji, gdy wartości XPos i YPos zostaną pominięte przy wywoływaniu tej funkcji, okno InputBox zostanie wyświetlone na środku ekranu w poziomie i mniej więcej w jednej trzeciej wysokości ekranu.

Argumenty XPos i YPos muszą być podane łącznie. Jeżeli określisz tylko jeden z tych argumentów, pomijając drugi, okno InputBox zostanie wyświetlone tak, jakbyś nie podał żadnego z nich.

W funkcji InputBox w przeciwieństwie do MsgBox nie ma możliwości dostosowania liczby i nazw wyświetlanych przycisków. W kwestii przycisków jedyną dostępną opcją jest domyślny zestaw dwóch przycisków - OK oraz Cancel.

Poniżej znajdują się dwa przykłady funkcji InputBox, składające się z fragmentu kodu oraz obrazka pokazującego jak zostało w danej sytuacji wyświetlone okno z zapytaniem. (Przykłady są przeznaczone do wywołania w oknie Immediate, o czym świadczy znak zapytania na poczatku wiersza, więc jeżeli chcesz je przetestować własnoręcznie, zrób to właśnie w oknie Immediate).

Okno z zapytaniem o datę urodzenia i wartością domyślną 3 stycznia 1983, położone w odległości 1 cala od góry i 1 cala od lewej krawędzi ekranu.
 
?InputBox("Podaj datę urodzenia", "Data urodzenia", #1983-01-03#, 1440, 1440)

InputBox z zapytaniem o datę urodzenia

Okno z zapytaniem o wysokośc pensji brutto i wartością domyślną 4000, wyświetlony w domyślnym miejscu na ekranie.
 
?InputBox("Podaj pensję brutto", "Pensja brutto", 4000)

InputBox z zapytaniem o wysokość pensji brutto

Przykłady prostych aplikacji komunikujących się z użytkownikiem

Aby utrwalić wiedzę zdobytą w dotychczasowych lekcjach, przeanalizuj umieszczone poniżej przykłady dwóch niewielkich aplikacji korzystających z omówionych w niniejszej lekcji sposobów komunikacji z użytkownikiem oraz z kilku innych funkcjonalności przedstawionych w poprzednich lekcjach.

Obliczanie pensji netto

Pierwszy przykład będzie się opierał na omawianej już i kilkakrotnie modyfikowanej funkcji do obliczania pensji netto. Dodatkowym elementem będzie jednak pobieranie informacji o pensji brutto bezpośrednio od użytkownika, do czego wykorzystana zostanie funkcja InputBox, oraz wyświetlenie obliczonej pensji netto w oddzielnym oknie zapomocą funkcji MsgBox.

1
2
3
4
5
6
7
8
9
10
Sub zarobki()
    Dim pensjaBrutto As Long
    Dim pensjaNetto As Long

    pensjaBrutto = InputBox("Podaj wysokość pensji brutto", "Pensja brutto")
    pensjaNetto = pensjaPoOpodatkowaniu(pensjaBrutto)

    Call MsgBox("Twoja pensja netto wynosi: " & pensjaNetto, _
                        vbOKOnly, "Pensja netto")
End Sub
1
2
3
Function pensjaPoOpodatkowaniu(podstawa As Long) As Long
    pensjaPoOpodatkowaniu = podstawa - (podstawa * 0.18)
End Function

Większość przedstawionego powyżej kodu powinna być Ci już znana z poprzednich lekcji.

W wierszach 2-3 zadeklarowane są dwie zmienne typu Long: pensjaBrutto i pensjaNetto.

W wierszach 5-6 do zmiennej pensjaBrutto zostaje przypisany wynik działania funkcji InputBox, a więc to, co użytkownik wpisze w wyświetlonym oknie.

Przy wywołaniu funkcji InputBox, oprócz obowiązkowego argumentu Prompt, który przyjmuje wartość Podaj wysokość pensji brutto, podany został również argument opcjonalny Title, do którego przypisano tekst Pensja brutto (oznacza to, że taki tekst pojawi się na niebieskim pasku u góry okna z zapytaniem).

Zwróć uwagę, że funkcja InputBox zwraca wartości tekstowe, więc nawet jeśli wpiszesz w jej oknie liczbę lub datę, to wynikiem funkcji będzie tekstowa reprezentacja tej liczby lub daty. Na szczęście, jak wspomniano w lekcji omawiającej typy danych, przy przypisywaniu tekstowych reprezentacji liczb do zmiennych liczbowych, język VBA automatycznie konwertuje je do wartości liczbowych.

W wierszu 7 do zmiennej pensjaNetto zostaje przypisany wynik funkcji pensjaPoOpodatkowaniu, w której argumentem podstawa jest wartość zmiennej pensjaBrutto, czyli wartość, którą użytkownik podał w oknie InputBox.

W wierszu 9 zostaje wywołana funkcja MsgBox, która wyświetla na ekranie informację o wysokości pensji netto dla podanej wcześniej pensji brutto.

Jak widzisz na podstawie argumentów podanych przy wywoływaniu funkcji MsgBox, okno komunikatu będzie posiadało tylko przycisk OK, a na pasku tytułu pojawi się napis Pensja netto.

Powyższa aplikacja pozostawia jeszcze trochę do życzenia, głównie w kwestii sprawdzania poprawności danych. Wyobraź sobie bowiem, że użytkownik w oknie z pytaniem o wysokość pensji brutto zamiast wartości liczbowej wpisze tekst. W dopiętej na ostatni guzik aplikacji w takiej sytuacji powinien pojawiać się komunikat o nieprawidłowym formacie danych wraz z informacją, że w tym polu wymagana jest liczba.

Omówiona przed chwilą aplikacja nie jest uodporniona na tego typu zachowania użytkowników i w przypadku podania wartości tekstowej zostanie wygenerowany błąd, a całe makro przerwie swoje działanie wyświetlając na ekranie zupełnie niezrozumiały dla końcowego użytkownika komunikat VBA zawierający numer błędu. W profesjonalnych aplikacjach nie ma miejsca na takie sytuacje - użytkownik nigdy nie powinien oglądać komunikatów o błędach powstałych podczas wykonywania kodu.

W kolejnej lekcji poznasz jednak instrukcję warunkową If ... Then, która doskonale nadaje się do tego, żeby wyeliminować tę niedoskonałość aplikacji.

Obliczanie liczby przeżytych miesięcy, tygodni, dni itd.

Drugi przykład prezentuje aplikację, która na podstawie podanej przez użytkownika daty urodzenia oblicza liczbę przeżytych przez niego miesięcy, tygodni oraz dni i wyświetla te informacje w oknie z komunikatem.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Sub obliczanieCzasu()
    Dim dataUrodzenia As Date
    Dim miesiace As Long
    Dim tygodnie As Long
    Dim dni As Long

    dataUrodzenia = InputBox("Podaj datę urodzenia", "Data urodzenia")
    miesiace = DateDiff("m", dataUrodzenia, Date)
    tygodnie = DateDiff("ww", dataUrodzenia, Date)
    dni = DateDiff("d", dataUrodzenia, Date)

    Call MsgBox("Dotychczas przeżyłeś: " & vbCrLf & _
                miesiace & " miesięcy" & vbCrLf & _
                tygodnie & " tygodni" & vbCrLf & _
                dni & " dni", vbOKOnly, "Ile już przeżyłeś")

End Sub

W wierszach 2-5 znajdują się deklaracje zmiennych wykorzystanych w tej aplikacji. Pierwszą z nich jest zmienna typu datowego dataUrodzenia, do której, jak wskazuje jej nazwa, przypisana zostanie później wprowadzona przez użytkownika data urodzenia. Oprócz niej w aplikacji wykorzystane są trzy zmienne typu Long - miesiace, tygodnie oraz dni, do których przypisana będzie odpowiednia liczba miesięcy, tygodni i dni.

W wierszu 7 do zmiennej dataUrodzenia zostaje przypisany wynik działania funkcji InputBox, czyli data, jaką użytkownik wpisze w wyświetlonym oknie.

W kolejnych trzech wierszach do zmiennych miesiace, tygodnie i dni przypisana zostaje liczba miesięcy, tygodni i dni jakie upłynęły od daty urodzenia wprowadzonej przez użytkownika do daty dzisiejszej.

Do obliczenia różnicy pomiędzy dwiema datami - dzisiejszą i podaną przez użytkownika - zastosowano wbudowaną funkcję DateDiff, której działanie omówiono szczegółowo w poprzednim rozdziale.

Aby pobrać aktualną datę wykorzystano natomiast inną wbudowaną funkcję - Date.

Po obliczeniu wszystkich różnic w datach i przypisaniu ich do zmiennych, w wierszach 12-15 zostaje wywołane okno komunikatu, w którym wyświetlono wartości tych zmiennych.

Określając tekst komunikatu kilkukrotnie zastosowano słowo kluczowe vbCrLf, co pozwoliło na wyświetlenie każdej wyliczonej wartości w oddzielnej linijce.