Nov 16 2009

Wtorki z VBA – kurs dla początkujących cz. 6 – Funkcje dla zaawansowanych

Posted by Marcin

W dzisiejszym poście będę kontynuował temat funkcji użytkownika. W poprzednim opisałem najważniejsze podstawy tworzenia funkcji, generalnie wystarczające do codziennych i nieprofesjonalnych zastosowań. Na dziś zostawiłem nieco bardziej zaawansowane zagadnienia - przydatne wtedy, gdy robimy rozwiązania bardziej wyszukane, lub które mają być udostępnione światu.

Argumenty opcjonalne

Argumenty opcjonalne to takie, których nie musimy podawać - w przypadku ich braku funkcja użyje wartości domyślnej. Przykładem może być funkcja PMT(Stopa, Liczba_rat, Wa, [Wp], [Typ]) - gdzie argumenty Wp oraz Typ są opcjonalne. Jeśli do tej funkcji nie przekażemy tych argumentów, Excel przyjmie dla wartości domyślne, odpowiednio 0 oraz 0. Innymi słowy, poniższe dwa wywołania funkcji zwrócą tę samą wartość (miesięczna rata pożyczki 200 000 zł, udzielonej na 30 lat, oprocentowanej 6% w skali roku i płatnościach na koniec miesiąca):

 
=PMT(6%/12;360;200000)
=PMT(6%/12;360;200000;0;0)
 

Argumenty opcjonalne definiujemy poprzedzając nazwę argumentu słowem kluczowym Optional. Musimy również pamiętać, że argumenty opcjonalne muszą znajdować się za wymaganymi (na końcu listy). Od razu w nagłówku funkcji możemy również podać wartość domyślną (użytą w przypadku braku argumentu) w następujący sposób:

 
Function NazwaFunkcji(arg_wymagany,
[Optional arg_opcjonalny [As typ_danych]
[= wartosc_domyslna]])
 

Spróbujmy teraz zaimplementować podobny mechanizm w naszej funkcji ProwizjaMaklerska. Założenie jest takie, że pierwszym argumentem będzie WartośćZlecenia, a drugim - ProwizjaMinimalna, przy czym ProwizjaMinimalna będzie argumentem opcjonalnym - w przypadku jego braku, minimalna prowizja za zlecenie będzie równa 0, czyli biuro maklerskie będzie nam naliczało koszt liniowo. Oto przykład:

 
Function ProwizjaMaklerska(WartoscZlecenia As Currency,
Optional ProwizjaMinimalna As Variant = 0) As Currency
 
Const StawkaProwizji = 0.0029
 
    ProwizjaMaklerska = StawkaProwizji * WartoscZlecenia
    If ProwizjaMaklerska < ProwizjaMinimalna Then
        ProwizjaMaklerska = ProwizjaMinimalna
    End If
 
End Function
 

Na poniższym obrazku mamy test obu wywołań funkcji (kolumna "B": =ProwizjaMaklerska(A2;3) oraz kolumna "C": =ProwizjaMaklerska(A2)):

Argumenty opcjonalne

Jak widzicie, funkcja działa również z jednym argumentem. Oczywiście argumentów opcjonalnych może być więcej, należy tylko pamiętać, że muszą one znajdować się za argumentami wymaganymi.

Nieokreślona liczba argumentów

Przykładem wbudowanej funkcji o nieokreślonej liczbie argumentów jest funkcja ŚREDNIA(liczba1, liczba2…), gdzie tych liczbx może być więcej i programiści z góry nie określili jaka to będzie liczba.

My również możemy napisać funkcję, która będzie pobierać nieokreśloną z góry liczbę argumentów. Kluczem do tego jest użycie tablicy poprzedzonej słowem ParamArray jako ostatniego lub jedynego argumentu. Argument ten zawsze jest opcjonalny (choć nie stosuje się słowa Optional) i zawsze ma typ Variant. Definicja wygląda następująco:

 
Function NazwaFunkcji([arg_wymagane],
ParamArray NazwaTablicy() [as Variant]) [As typ_danych]
 

Arg_wymagane mogą zostać pominięte, a NazwaTablicy jest nazwą tablicy przechowującą naszą listę argumentów. Jak to wygląda w praktyce? Oto kolejna implementacja funkcji zwracającej sumę kwadratów liczb podanych jako argumenty:

 
Function SumaKwadratow(ParamArray ListaArgumentow()
As Variant) As Long
 
Dim Argument As Variant
 
    For Each Argument In ListaArgumentow
        SumaKwadratow = SumaKwadratow + Argument ^ 2
    Next Argument
End Function
 

W tym wypadku możemy tę funkcję wywołać z różna liczbą argumentów:

 
=SumaKwadratow(2)
=SumaKwadratow(2;3)
=SumaKwadratow(2;3;4)
 

Funkcja tablicowa (zwracająca tablicę wartości)

Możemy również tworzyć funkcje tablicowe, czyli takie, które zwracają tablicę wartości (patrz post o zastosowaniu formuł tablicowych). Aby uzyskać poprawnie wyniki należy je potwierdzić kombinacją klawiszy CTRL+SHIFT+ENTER, uprzednio zaznaczając zakres komórek, w których chcemy otrzymać wyniki.

Wyniki w postaci tablicy możemy uzyskać po zastosowaniu funkcji Array. Prosty przykład funkcji zwracającej poziomą tablicę nazw dni tygodnia przedstawiam poniżej:

 
Function DniTygodnia()
    DniTygodnia = Array("Poniedziałek", "Wtorek",
"Środa", "Czwartek", "Piątek", "Sobota", "Niedziela")
End Function
 

Aby sprawdzić działanie funkcji zaznaczamy poziomo siedem komórek (np. od A1 do G1), na pasku formuł wpisujemy =DniTygodnia() i zatwierdzamy poprzez CTRL+SHIFT+ENTER.

Zwracanie kodu błędu

Tworząc formuły musimy pamiętać również o tym, aby poinformować użytkownika o problemach w przypadku gdy nasza funkcja napotka takowe. Standardowe funkcje Excela zwracają wtedy specjalne wartości błędu, takie jak #DZIEL/0!, #N/D! itd. Rodzaj zwracanej wartości (rodzaj błędu) zależy od tego, jaka problem funkcja napotkała.

Moglibyśmy w zasadzie przypisać takiej funkcji łańcuch tekstowy np. ProwizjaMaklerska = "#ARG!" w przypadku, gdy brakuje argumentów, ale napotykamy tutaj na następujący problem: otóż inne funkcje odwołujące się do komórki z taką funkcją nie będą w stanie rozpoznać błędu (będą rozpoznawać wartość tekstową "#ARG!" - a to nie jest to samo co kod błędu!) - dotyczy to zwłaszcza funkcji informacyjnych służących do obsługi błędów: CZY.BŁ(), CZY.BŁĄD().

Musimy zatem odrzucić to rozwiązanie. Aby zwrócić rzeczywistą wartość błędu funkcji należy użyć funkcji CVErr języka VBA, która zmienia numer błędu na jego rzeczywistą wartość. Użycie takiej funkcji jest banalne:

 
NazwaFunkcji = CVErr(StałaBłędu)
 

Stałe błędów zostały zdefiniowane następująco:

  • xlErrDiv0 (#Dziel/0!),
  • xlErrNA (#N/D!),
  • xlErrName (#NAZWA?),
  • xlErrNull (#ZERO!),
  • xlErrNum (#LICZBA!),
  • xlErrRef (#ADR!),
  • xlErrValue (#ARG!),

Przykład użycia funkcji CVErr:

 
ProwizjaMaklerska = CVErr(xlErrValue)
 

Należy pamiętać, aby używając funkcji CVErr do obsługi błędów w funkcji zmienić typ danych wartości zwracanej przez funkcję (typ danych funkcji) na Variant.

Kontrola wykonania funkcji

Każdy, kto tworzy nowe funkcje kiedyś stanie przed pytaniem: kiedy moja funkcja zostanie przeliczona ponownie? Zwykle (domyślnie) jest tak, ze funkcje użytkownika wykonuje obliczenia wtedy, gdy zostanie zmodyfikowany przynajmniej jeden z jej argumentów.

Możemy jednak stanąć przed koniecznością wymuszenia częstszych obliczeń w funkcji. Jeśli umieścimy w procedurze Function poniższą instrukcję nasza funkcja zostanie ponownie uruchomiona każdorazowo przy wykonaniu jakichkolwiek obliczeń w arkuszu (przy modyfikacji dowolnej komórki).

 
Application.Volatile True
 

Domyślnie właściwość Volatile ma wartość False.

Dodawanie opisu do funkcji

Opis funkcji to nic innego jak krótkie streszczenie lub pomoc, która pokazuje się w oknie dialogowym Wstaw funkcję przy wybraniu funkcji. Warto dodawać opisy funkcji wtedy, kiedy nasze projekty są udostępniane innym użytkownikom.

W VBA Excela istnieje bardzo wygodny sposób na dodanie opisu funkcji - dokonujemy tego za pomocą metody:

 
Application.MacroOptions Macro:="Nazwa_funkcji",
Description:="Opis funkcji"
 

Przykład:

 
Application.MacroOptions Macro:="ProwizjaMaklerska",
Description:="Funkcja obliczająca prowizję od zlecenia
pobieraną przez biuro maklerskie."
 

Musimy pamiętać, że powyższa instrukcja powinna być wykonana tylko raz, zatem jeśli dystrybuujemy nasze funkcje w dodatku Excela, najlepiej jest umieścić jet w module ThisWorkbook w obsłudze zdarzenia Workbook_AddinInstall.

Przypisanie funkcji do kategorii

Podobnie jak w przypadku opisu funkcji umieszczenie naszej funkcji w odpowiedniej kategorii (np. Matematyczne, Tekstowe, Statystyczne) ułatwia potencjalnemu użytkownikowi szybkie odnalezienie funkcji. Jeśli chcemy dodać naszą funkcję do odpowiedniej kategorii korzystamy również z metody MacroOptions:

 
Application.MacroOptions Macro:="Nazwa_funkcji",
Category:=Nr_kategorii
 

Ta instrukcja też powinna być wykonana tylko raz, dlatego przypisanie funkcji do kategorii powinno odbywać się razem z dodaniem opisu:

 
Application.MacroOptions Macro:="ProwizjaMaklerska",
Category: = 1, Description:="Funkcja obliczająca prowizję
od zlecenia pobieraną przez biuro maklerskie."
 

W tym wypadku naszą funkcję przypisaliśmy do kategorii Finansowe. Stałe kategorii przedstawione są poniżej:

1 Financial
2 Date & Time
3 Math & Trig
4 Statistical
5 Lookup & Reference
6 Database
7 Text
8 Logical
9 Information
10 Commands
11 Customizing
12 Macro Control
13 DDE/External
14 User Defined

Co ciekawe, możemy również stworzyć własną kategorię - podając zamiast liczby nazwę naszej nowej kategorii w cudzysłowach, np.:

 
Application.MacroOptions Macro:="ProwizjaMaklerska", _
Category: = "Maklerskie", Description:="Funkcja obliczająca prowizję
od zlecenia pobieraną przez biuro maklerskie."
 

Jeśli taka kategoria już istnieje, nasza funkcja zostanie do niej dołączona, w przeciwnym wypadku zostanie utworzona nowa kategoria.

Powiązane artykuły:

Leave a Reply