MS Office 2007 VBA
Nahrávání makra
Word

Po opatření dokumentu makrem dokument zavřete a uložte jako dokument s podporou maker. Dále pokračutje v práci už jen v dokumentu s podporou maker (Přípona .docm)
Excel
Nahrávání maker v Excelu se od Wodru liší jen tím, že není k dispozici tlačítko pro přerušení nahrávání.
Po opatření sešitu makrem sešit zavřete a uložte jako sešit s podporou maker. Dále pokračutje v práci už jen v sešitu s podporou maker (Přípona .xlsm)
Spuštění makra
Jak ve Wordu tak i v Excelu je ochrana před spouštěním maker. Tuto ochranu lze vypnout v Centru zabezpečení operačního systému MS Windows Vista nebo novějšího.

Mnohem bezpečnější je zvolit Zakázat všechna makra s oznámením a makra povolovat po každém otevření sešitu.
Jinou možností je vytvořit si certifikát.


Změna zabezpečení se projeví až po zavření a otevření aplikace Word nebo Excel.
Přiřazení makra klávesové zkratce
Klávesové zkratky přiřaďte až po nastavení zabezpečení.
Word

Klikneme na tlačítko "Vlastní".

Excel
Přiřazení makra klávesové zkratce v Excelu je přímo v nabídce "Makra - Možnosti".
Přiřazení makra tlačítku na panelu nástrojů Rychlý přístup
Word

Excel
Přiřazení makra tlačítku na panelu nástrojů Rychlý přístup v Excelu se od Wodru příliš neliší.
Přiřazení makra objektu
Objektem je například obrázek nebo graf. Je to možné pouze v Excelu pomocí místní nabídky - "Přiřadit makro..."
Spuštění makra událostí
Jak ve Wordu tak i v Excelu se událost nastavuje v editoru jazyka Visual Basic.
Další možnosti spouštění maker
Ribbon
Makra se dají spouštět i pomocí tlačítek přidaných na pás karet (ribbon). Ribbon se upravuje pomocí tvorby XML dokumentu.
Word
Ve Wordu lze makra umístit do šablony "Normal.dot" v editoru jazyka Visual Basic.
Excel
V Excelu lze makra umístit do Osobního sešitu maker, který neexistuje, dokud do něj není přiřazeno alespoň jedno makro. Potom se Osobní sešit maker (soubor "Personal.xlsb") otevírá automaticky při staru Excelu. Osobní sešit maker je skrytý. Je možné jej zobrazit pomocí příkazu Zobrazit.
Formuláře
Word i Excel umožňuje tvorbu formulářů pro elektronický sběr dat.
Formuláře obsahují ovládací prvky dostupné na kartě Vývojář.
Formuláře v Excelu mají oproti Wordu bohatší výběr druhů ovládacích prvků. Jsou-li však respondenti méně zkušení v práci s kancelářskými aplikacemi, je lepší vytvořit pro ně formulář ve Wordu.
Níže uvedené příklady popisují takové typy formulářů, při jejichž tvorbě není nutné používat jazyk VBA.
Ve verzi MS Word 2007 přibyly nové ovládací prvky formulářů, které se však dají použít až s využitím programování v jazyce VBA a znalostí o XML formátu dat nebo aplikace InfoPath, která je dostupná v profesionálních verzích MS Office 2007. Tato řešení jsou vhodná v případě, kdy je potřeba často dostávat data z formulářů do podnikových databází.
V případě, kdy je potřeba vytvořit a použít formulář pro soukromé účely nebo jako rychlé příležitostné podnikové řešení, je třeba využít ovládacích prvků ze starších verzí MS Office. Příklady v tomto materiálu popisují pouze tento typ řešení a dále takzvané UserForms.
Word
Ve Wordu použijeme pro tvorbu formuláře Nástroje starší verze.

Z menu, které se objeví, budeme používat pouze Starší formuláře (Legacy Forms). Ovládací prvky ActiveX vyžadují programování ve VBA.

Po kliknutí na vybraný ovládací prvek se prvek vloží do dokumentu Wordu.
Ovládací prvek vložený do dokumentu Wordu se dále upraví pomocí karty Vlastnosti.

Ovládací prvky v dokumentu Wordu se dají kombinovat s textem a obrázky.
Před rozesláním formuláře respondentům je potřeba formulář uzamknout, protože potom je možné do ovládacích prvků ukládat dotazované informace. Zároveň není možné editovat text kolem ovládacích prvků. Proto je nutné formulář vytvořit tak, aby všechny informace, které má respondent vyplnit, se zadávaly do ovládacích prvků. Uzamknutí se provádí pomocí tlačítka Uzamknout dokument na kartě Vývojář.

Po kliknutí na tlačítko Uzamknout dokument se objeví nabídka, kterou nastavíme dle následujícího obrázku a klikneme na tlačítko Použít zámek.

Nezadáme-li heslo a klikneme na tlačítko OK, bude formulář připraven k vyplňování respondenty, ale nebude zaheslován.

Uzamnčený formulář lze pro účely jeho dalšího vývoje odemknout.

Vytvoříte-li formulář pomocí ovládacích prvků pro starou verzi, tak můžete formulář uložit ve verzi 2003 a respondenti jej budou moci vyplnit jak ve verzi 2003 tak ve verzi 2007.
Formuláře vrácené od respondentů se uloží takovým způsobem, aby výsledkem byl textový soubor, ve kterém jsou pouze data formulářů. To se zajistí zaškrtnutím volby Ukládat data formulářů jako textový soubor s oddělovači v Možnostech aplikace Word předtím, než se dokument uloží.

Při této úloze se vyplatí využít VBA pro napsání makra, které uloží data formulářů z více dotazníků najednou do jednoho souboru, protože ten lze potom jednoduše importovat do Excelu, kde bude výsledek dotazování všech respondentů analyzován. Dokument s takovým makrem je k dispozici zde pro dotazníky s příponou doc a docx.
Excel
Formulář v Excelu je sešit s ovládacími prvky, které jsou propojeny s buňkami.
Ovládací prvky jsou na kartě Vývojář. Budeme používat jen tlačítka ze sekce Ovládací prvky formuláře.

3 poslední tlačítka ze sekce Ovládací prvky formuláře (Textové pole, Seznam se vstupním polem a Rozevírací seznam se vstupním polem) nefungují, protože se týkají dialogových listů (DialogSheets) starší verze Excelu stejně jako tlačítko Spustit dialog.
Po kliknutí na vybraný ovládací prvek se ukazatel myši změní na křížek a jeho táhnutím se stisknutým levým tlačítkem myši se na listu nakreslí tvar ovládacího prvku a puštěním tlačítka se ovládací prvek do listu vloží.

První z ovládacích prvků formuláře Tlačítko má smysl pouze po naprogramování makra s ním spojeného, takže jej nebudeme používat.
Ovládací prvek Textové pole v Excelu chybí, protože se dá nahradit buňkou na listu.
Po vložení ovládacího prvku na list se upraví jeho vlastnosti pomocí nabídky Formát ovládacího prvku..., která se vyvolá kliknutím pravým tlačítkem na ovládací prvek.

U každého typu ovládacího prvku je především nutné vyplnit Propojení s buňkou.

Předtím, než se formulář rozešle respondentům, je vhodné jej zamknout, aby respondenti měli přístup pouze k ovládacím prvkům a formulář nepoškodili.
Každá buňka na listu sešitu má implicitně nastaveno zamknutí, které se projeví po zamknutí listu. Před zamknutím je nutné u všech buněk propojených s ovládacími prvky vypnout v nabídce Formát buněk... jejich zamknutí, aby se mohl jejich obsah měnit vkládáním dat do ovládacích prvků. Zamknutí se vypne také u buněk, které slouží místo textových polí.


Zamknou se jednotlivé listy s formulářem pomocí nabídky na kartě Revize.

Po zamknutí není možné vkládat informace do buněk kromě tech, které jsou propojené s ovládacími prvky, a ty se mění podle toho, jak uživatel nastaví propojený ovládací prvek.
Formuláře vrácené od respondentů se zpracují tak, aby vznikla excelovská tabulka s řádky patřícími jednotlivým respondentům a sloupky patřícími jednotlivým otázkám. Pro tuto úlohu existuje doplněk aplikace Excel zvaný Průvodce šablonou se sledováním dat, který již není dodáván s programovým balíkem MS Office a od roku 2012 již ani není oficiálně dostupný na stránkách firmy Microsoft.
Doplněk se jmenuje WZTEMPLT.XLA a je ve formě samorozbalovacího programu TMPLWIZ.EXE, ale po jeho spuštění kliknutím na něj se soubory v něm zabalené nikde neobjeví kvůli nekompatibilitě s novými operačními systémy Windows. Proto je nutné soubory z něj vyjmout nějakou externí aplikací, například programem 7-Zip.

V adresáři, kde Excel hledá dodatečné doplňky, se vytvoří adresář TemplateWizard a do něj se zkopírují soubory z archivu TMPLWIZ.EXE.

Použití je zhruba takové, že se doplněk připojí k aplikci Excel,




potom se na pásu karet objeví nová karta Doplňky s tlačítkem Template Wizard.

Po kliknutí na tlačítko Template Wizard se určí název a umístění šablony, kterou průvodce vytvoří,

název a umístění databáze (výsledné tabulky s daty formulářů), kterou průvodce vytvoří,

nadefinují se buňky ve formuláři, které obsahují data formulářů.

Průvodce také umožňuje více souborů s vyplněnými dotazníky uložit do databáze najednou.





Výsledná databáze je umístěna v adresáři, který byl nastaven pomocí průvodce.

Ve starších verzích Excelu fungovalo ještě otevření formuláře na základě šablony vytvořené Průvodcem šablonou se sledováním dat (pomocí nabídky Nový pod Tlačítkem Office),

po jehož vyplnění a uložení se data automaticky odeslala do databáze. V případě, že budou data sbírána rozesláním formulářů a jejich následným hromadným zpracováním, je to však funkčnost, kterou nepotřebujeme.
Programovací jazyk VBA
Jazyk VBA je zkratka slov Visual Basic for Applications.
Je to objektově orientovaný interpretovaný programovací jazyk vytvořený společností Microsoft pro použití v rámci aplikací.
Aplikacemi nejsou jen aplikace v rámci MS Office (Excel, Word, Access, PowerPoint a Outlook) ale i jiné windowsovské aplikace, například Microsoft MapPoint, Microsoft Visio, Word Perfect, ArcGIS, AutoCAD, Corel Draw, System Architect a další.
Jeho základem je jazyk Visual Basic, který je založen na jazyce BASIC.
BASIC je zkratka slov Beginner’s All-Purpose Symbolic Instruction Code.
Jazyk BASIC byl navržen tak, aby byl uživatelsky přívětivý tak, že co nejvíce připomíná anglický jazyk.
Visual Basic má v názvu slovo visual, protože nabízí programovací techniky umožňující pracovat myší s ovládacími grafickými prvky.
Jazyk Visual Basic for Applications se skládá ze základních objektů a příkazů jazyka Visual Basic a objektů a příkazů specifických pro aplikace MS Office.
VBA vždy pracuje s hostitelskou aplikací (například Access nebo Word), což znamená, že hostitelská aplikace musí být vždy otevřena, když pracuje kód VBA.
Jinou možností je využití nástrojů Visual Studio Tools for Office, kterými se vytvářejí samostatné aplikace v rámci Microsoft .NET Framework.
Práce s nápovědou
Umístíme-li kurzor do názvu objektu v kódu VBA v editoru VBA a stiskneme klávesu F1, objeví se kontextová nápověda k tomuto objektu.
Napíšeme-li platný název objektu a bezprostředně za něj tečku, objeví se nabídka metod a vlastností, ze které si můžeme vybrat myší.
Má-li vybraná metoda parametry, objeví se po napsání závorky nebo mezery za tuto metodu seznam parametrů pomáhající tyto parametry vyplnit.
2 výše uvedené způsoby chování jsou příkladem automatického dokončování nazývané IntelliSense.
Seznam všech hesel nápovědy je také možné vyvolat kliknutím na tlačítko Help v editoru VBA.
Při psaní kódu vše pište malými písmeny. Nepřepíše-li se název objektu na velké počáteční písmeno, znamená to že je v něm překlep.
Makro
Makro je sekvence příkazů, které se dají spustit jedním příkazem.
Makro se dá pořídit nahráním nebo editací zdrojového kódu.
Vhodné akce pro makra:
- Vícenásobná nahrazování
- Akce spojené s otevíráním nových dokumentů
- Práce s více dokumenty najednou
Objektový model aplikace
Objektový model je hierarchie všech objektů aplikace.
Například v Excelu je následující hierarchie objektů: Application - Workbook - Worksheet - Range.
Informace o objektovém modelu aplikace jsou dostupné v editoru VBA (Object Browser vyvolatelný klávesou F2) nebo online.
Při programování ve VBA většinou není nutné vytvářet vlastní objekty. Stačí využívat již vytvořené objekty.
Objekt je vše, s čím můžeme v aplikaci manipulovat.
Vlastnost, metoda a událost objektu
S objekty lze manipulovat 3 způsoby:
- Lze číst a měnit vlastnosti objektu.
- Lze přimět objekt k vykonání akce aktivací metody, kterou objekt umí.
- Lze napsat program, který se spustí, kdykoli se objektu stane určitá událost.
Vlastnost objektu
Na vlastnost objektu se odkazujeme způsobem Objekt.Vlastnost
Vlastnost objektu měníme způsobem Objekt.Vlastnost = hodnota
Vlastnost objektu zjišťujeme způsobem Proměnná = Objekt.Vlastnost
Metoda objektu
Metodu objektu aktivujeme způsobem Objekt.Metoda
Například
Range("a1").Select
Událost objektu
Událost u objektu nastavujeme v editoru VBA.

V prohlížeči projektu máme vybraný List1.
Pod prohlížečem projektu vidíme seznam vlastností listu List1, kde je můžeme i měnit.
Po dvojím kliknutí na objekt v prohlížeči projektu se napravo od prohlížeče projektu objeví prostor pro kód VBA.
Nad prostorem pro kód vybereme nalevo objekt (zde Worksheet) a napravo událost.
Přitom se do prostoru pro kód automaticky předepíše obal pro kód, který můžeme buďto přímo napsat do něj nebo místo něj napsat název procedury, která je v jiném modulu.
Přístup k objektu
Nižší objekty v objektové hierarchii jsou vlastnostmi objektů, jejichž součástmi jsou.
Jen málokdy je nutné přistupovat k objektu vypsáním celé hierarchie:
Application.ActiveWorkbook.ActiveSheet.Range("a1").Value = "ahoj"
Chceme-li vyplnit buňku A1 na aktivním listu, tak stačí kód
Range("a1").Value = "ahoj"
Chceme-li vyplnit buňku na jiném než aktivním listu, musíme tento list do hierarchie uvést a to lze 2 způsoby:
Výše uvedený kód funguje pro aktivní sešit. Chceme-li v makru manipulovat s jiným než aktivním sešitem, je způsob analogický příkladu s listy sešitu. Jeho názvem je diskový název souboru, stejně jako u objektu Documents ve Wordu.
Kolekce objektů
Kolekce je množina podobných objektů umožňující jedním příkazem manipulovat se všemi objekty v kolekci.
Objekt Worksheets je kolekce.
Objekt Worksheets(1) je první objekt z kolekce Worksheets.
Kolekce objektů má jinou množinu vlastností a metod než jednotlivé objekty v této kolekci.
V kolekci objektů je zpravidla jeden z nich aktivní (vybraný, je na něm fokus) a na ten se lze odkazovat pod názvem objektu začínajícím na Active, například ActiveSheet.
Mezi objekty Workbook a Document je navíc objekt ThisWorkbook a ThisDocument, které označují excelovský sešit a wordovský dokument, ve kterém běží kód VBA.
Objekt Worksheet (a jemu analogické Workbook a Document) můžeme použít jako datový typ ale nikoli jako objekt, u nějž voláme metodu nebo vlastnost. V takovém případě použijeme syntaxi Worksheets(1) nebo Worksheets("List1").
Kolekce Sheets versus Worksheets v Excelu
Kolekce Sheets obsahuje kolekci Worksheets a Charts (Graf lze umístit jako nový list.) ale také DialogSheets (nyní nahrazené za UserForms), Excel4MacroSheets a Excel4InternationalMacroSheets z důvodu zachování kompatibility se staršími verzemi Excelu.
Základní prvky programů v jazyce VBA
V jazyce VBA se píší 2 základní typy programů, které se společně nazývají procedury (procedures):
- sub procedury (Sub Procedures nebo subprocedures začínající slovem Sub.)
- funkce (User-Defined Functions - UDF začínající slovem Function.)
Typickým použitím sub procedury je vykonání nějaké akce. Range("a1").Select
Typickým použitím funkce je výpočet hodnoty a její předání do proměnné. i = Len("ahoj")
Programy obsahují názvy (identifikátory) objektů, metod, vlastností a procedur, konstanty, proměnné, řídící struktury a komentáře.
Konstanty
Konstanty se dělí na
- vestavěné (built-in)
- definované programátorem (user-defined)
Vestavěné konstanty
Mnoho vlastností a metod má své vlastní předdefinované konstanty.
U objektů Excelu tyto konstanty začínají písmeny xl.
U objektů Wordu tyto konstanty začínají písmeny wd.
U objektů VBA tyto konstanty začínají písmeny vb.
Například, objekt Window v Excelu má vlastnost WindowState, která rozeznává 3 vestavěné konstanty: xlNormal, xlMaximized a xlMinimized. Maximalizace aktivního okna by se například provedla příkazem ActiveWindow.WindowState = xlMaximized
V podobných příkazech jsou možné konstanty nabízeny funkcí IntelliSense, takže si je není třeba pamatovat.
Konstanty definované programátorem
Následující příkaz vytvoří konstantu DISCOUNT datového typu Single a dá jí hodnotu 0.4:
Const DISCOUNT As Single = 0.4
Konstantami mohou být pouze primitivní datové typy a řetězce, nikoliv objekty.
Proměnné
Proměnné se definují za klíčovým slovem Dim.
Stejně jako klíčové slovo Const, lze i klíčové slovo Dim nalézt v seznamu nápovědy k Microsoft Visual Basic v nabídce Microsoft Visual Basic Documentation - Visual Basic Language Reference - Statements.
Do proměnné lze přiřadit
- vlastnost objektu způsobem Proměnná = Objekt.Vlastnost
- objekt způsobem Set Proměnná = Objekt
Deklarace proměnných
Jazyk VBA implicitně nevyžaduje deklarování proměnné před tím, než je použita.
Výhoda: Dá se rychle napsat program.
Nevýhoda: Když v proměnné, jejíž název v programu použijeme několikrát, uděláme překlep, je to bráno jako nová proměnná a může vzniknout špatně odhalitelná sémantická chyba.
U velkých projektů (cca na víc než 10 řádků) je lepší nastavit vývojové prostředí tak, aby vyžadovalo proměnné před jejich použitím deklarovat. Na začátek modulu se napíše Option Explicit
Proměnné je možné deklarovat kdekoli v kódu, ale je dobrým zvykem deklarovat je na začátku programu.
Při deklarování proměnných je možné deklarovat pouze jméno proměnné a potom je tato proměnná typu Variant, což je univerzální datový typ,
Dim i
nebo jméno i datový typ proměnné
Dim i As Integer
Deklarování jména spolu s datovým typem proměnné je lepší než neúplná nebo žádná deklarace, protože
- při psaní kódu bude fungovat automatické dokončování (když je datovým typem objekt),
- při ladění kódu se bude kontrolovat, zda se do proměnné přiřazují hodnoty očekávaného typu a
- interpret VBA nemusí určovat typ proměnné za běhu programu a proto program bude běžet trochu rychleji.
Na co dát pozor
Po deklaraci
Dim a, b As Integer
je a typu Variant, protože jeho typ nebyl deklarován, a b je typu Integer.
Chceme-li mít a i b typu Integer, je správně následující deklarace:
Dim a As Integer, b As Integer
Řídící struktury
Základními řídícími strukturami algoritmů v jakémkoli jazyce je
Tyto řídící struktury mají různé varianty, které je vhodné kopírovat z nápovědy. Vhodné výchozí heslo v seznamu nápovědy k Microsoft Visual Basic pro obě řídící struktury je v nabídce Microsoft Visual Basic Documentation - Visual Basic Conceptual Topics - Looping Through Code.
Při psaní kódu kontroluje interpret jazyka VBA syntaktické chyby na každém řádku jednotlivě. Proto záleží na tom, kde je konec řádku.
Jednotlivé příkazy jazyka se obvykle píší každý na zvláštní řádek a neukončují se žádným oddělujícím znakem.
Pokud potřebujeme několik krátkých příkazů napsat na společný řádek, oddělují se dvojtečkou ":". Důvodem k tomu může být například použití jednořádkové varianty řídící struktury If...Then...Else.
Dlouhé řádky je možné rozdělit pomocí dvojice znaků mezera a podtržítko " _" umístěné na koncec řádku.
Znaky mezera a podtržítko se nedají použít pro rozdělení textového řetězce jakožto hodnoty proměnné typu String.
V takovém případě se použije rozdělení
"první řádek" & _
"druhý řádek"
Řídící struktury by se měly zvýrazňovat odsazováním řádků podle příkladů z nápovědy.
Komentáře
Komentáře slouží k popisu programu pro člověka.
Komentáře se interpretem VBA nevykonávají.
Komentáře začínají znakem apostrof - '.
Komentář na několik řádků musí mít apostrof na každém řádku.
Argumenty neboli parametry procedur VBA
Argumenty modifikují chování procedur, případně jsou jejich vstupem. Programátor stanovuje hodnoty argumentů. Některé argumenty se zadávají nepovinně, a když se jejich hodnota nestanoví, tak mají nějakou implicitní hodnotu stanovenou v nápovědě.
Specifikace argumentů pozicí nebo jménem
Procedury mají často více argumentů. Argumenty jsou pojmenované.
Příklad s funkcí MsgBox
Opsáno z nápovědy:
MsgBox(prompt[, buttons] [, title] [, helpfile, context])
Funkce MsgBox má argumenty pojmenované prompt, buttons, title, helpfile, context.
Parametr prompt je povinný (v nápovědě Required).
Parametry v hranatých závorkách jsou nepovinné (v nápovědě Optional), zde buttons, title, helpfile, context.
Specifikace argumentů pozicí
MsgBox "Ahoj", , "Pozdrav"

Vynechané (nepovinné) argumenty se musí přeskočit pomocí čárek mezi argumenty.
Jsou-li na konci seznamů argumenty, které nechceme zadávat, tak je nemusíme vyjadřovat čárkami. Z toho důvodu, jsou málo používané argumenty uváděny na konci seznamů.
Specifikace argumentů jménem
MsgBox Title:="Pozdrav", prompt:="Ahoj"
Jsou-li argumenty pojmenované, je možné je uvádět v libovolném pořadí. Smysluplné použití je však v situaci, kdy z nabízeného většího množství argumentů potřebujeme specifikovat jen několik málo.
Argumenty v závorkách
Mnoho funkcí může plnit jak roli funkce (vypočítají hodnotu) tak roli sub procedury (vykonají akci).
Podle této role se mění syntaktická pravidla pro zápis funkce a jejích argumetů.
V předchozím příkladu byla funkce MsgBox použita jako sub procedura, protože vykonala akci spočívající v tom, že ukázala message box.
Funkce použitá jako sub procedura nemusí mít své argumenty v závorkách.
Funkce MsgBox použitá jako funkce vrací hodnotu tlačítka, na které uživatel kliknul, aby message box zmizel.
Za tím učelem musí mít funkce MsgBox vyplněn parametr buttons určující množinu tlačítek, která se mají na message boxu objevit.
Podle druhu stisknutého tlačítka může programátor zajistit větvení kódu.
Jakákoli funkce, která má vypočítat hodnotu, musí mít své argumenty v závorkách. Kdyby neměla žádné argumenty, musí za jejím identifikátorem (názvem) být prázdné závorky.
Funkce MsgBox
Parametr buttons ve funkci MsgBox
Funkce MsgBox bude tentokrát použita jako funkce a bude mít 2 tlačítka Abort, Retry a Ignore, bude mít ikonku s vykřičníkem, a 3. tlačítko bude implicitně vybráno.
V operačních systémech lokalizovaných do češtiny budou mít tlačítka zpravidla české názvy. Podrobnosti o lokalizaci jsou na stránce http://technet.microsoft.com/en-us/library/cc179091.aspx.
a = MsgBox("Ahoj", vbAbortRetryIgnore + vbExclamation + vbDefaultButton3, "Pozdrav")

Do proměnné a se uloží informace o tom, na jaké tlačítko uživatel kliknul.
Parametr buttons má hodnotu součtu vestavěných konstant vbAbortRetryIgnore, vbExclamation a vbDefaultButton3.
Vzhledem k tomu, že každá konstanta má kromě názvu i číselnou hodnotu, mohl předchozí příkaz vypadat i takto:
a = MsgBox("Ahoj", 562, "Pozdrav")
Je lepší první způsob volání message boxu, protože
- z názvů konstant lze vyčíst podobu message boxu,
- když je v programu zavedena pojmenovaná konstanta, je chyba ji do některých míst programu napsat jako hodnotou a ne jako jméno.
Dle nápovědy k funkci MsgBox jsou pojmenované konstanty pro parametr buttons rozděleny do skupin (0–5), (16, 32, 48, 64), (0, 256, 512) a (0, 4096). Z každé skupiny je možné si vybrat maximálně 1 konstantu. Hodnoty konstant jsou voleny tak, aby součty přípustných podmnožin konstant vzájemně nekolidovaly.
Návratové hodnoty funkce MsgBox
Návratové hodnoty každé funkce jsou popsány v nápovědě v části s nadpisem Return Values.
Návratové hodnoty funkce MsgBox jsou 1 až 7. Každé číslo odpovídá určitému druhu tlačítka. Místo čísel 1 až 7 je lepší psát názvy vestavěných konstant uvedené v nápovědě.
Máme-li v programu message box s více než jedním tlačítkem, dostane jeho použití smysl, až když otestujeme návratovou hodnotu message boxu a pro každou její možnou hodnotu napíšeme odpovídající větev programu. Vhodná řídící struktura pro tento úkol je If...Then...Else nebo Select Case.
Funkce InputBox
Funkce InputBox slouží ke zjištění hodnoty zadané uživatelem, takže smysl má pouze použít ji jako funkci.
b = InputBox("Zadej něco", "Zadávání", "něco")

Tlačítka OK a Cancel na input boxu nejsou ovlivnitelná argumenty funkce InputBox a nelze pro ně programovat zváštní větve programu. Mají už své dané funkce:
- Kliknutí na tlačítko OK uloží do proměnné b zadanou hodnotu.
- Kliknutí na tlačítko Cancel uloží do proměnné b prázdný řetězec, takže se přepíše předchozí hodnota b.
Dle nápovědy funkce InputBox vrací řetězec. (...returns a String containing the contents of the text box.)
To má za následek to, že po vykonání následujícího kódu
a = InputBox("Zadej číslo", "Zadávání")
b = InputBox("Zadej číslo", "Zadávání")
MsgBox a + b
se v message boxu objeví zřetězení zadaných čísel a ne jejich součet.
Součet hodnot zadaných do input boxu můžeme zajistit tím, že výsledek funkce InputBox zpracujeme funkcí Val.
a = Val(InputBox("Zadej něco", "Zadávání"))
b = Val(InputBox("Zadej něco", "Zadávání"))
MsgBox a + b
Kdybychom hodnoty číselného typu sčítali pomocí operátoru & pro zřetězení, objevilo by se v message boxu opět zřetězení zadaných čísel a ne jejich součet.
a = Val(InputBox("Zadej něco", "Zadávání"))
b = Val(InputBox("Zadej něco", "Zadávání"))
MsgBox a & b
Další možností, jak zajistit součet hodnot zadaných do input boxu místo zřetězení, je určení typu proměnných v jejich deklaraci. Potom nepotřebujeme funkci Val.
Dim a As Integer, b As Integer
a = InputBox("Zadej něco", "Zadávání")
b = InputBox("Zadej něco", "Zadávání")
MsgBox a + b
Detaily o chování operátorů + a & jsou na stránce http://msdn.microsoft.com/en-us/library/te2585xw%28VS.80%29.aspx.
Metoda Application.InputBox
Zatímco funkce MsgBox a InputBox je k dispozici ve Wordu i Excelu, Excel má navíc metodu Application.InputBox, která umožňuje kontrolovat zadávaný datový typ a zda bylo kliknuto na tlačítko Cancel.
Dle nápovědy je požadovaný datový typ zadávané hodnoty určován posledním argumentem Type. Není-li argument Type zadán, je požadovaným datovým typem zadávané hodnoty String.
Například následující kód vyvolá input box, který uloží do proměnné c číselnou hodnotu zadanou uživatelem.
c = Application.InputBox("Zadej číslo:", Type:=1)
Z příkladu je vidět, že i když je Application.InputBox metoda, používá se jako funkce.
Dle nápovědy lze možné hodnoty pro argument Type sčítat, takže potom input box umožňuje zadat víc různých datových typů. Například následující kód vyvolá input box, který umožní uživateli zadat do proměnné c libovolné číslo nebo text.
c = Application.InputBox("Zadej číslo", Type:=1 + 2)
Všechny možné hodnoty pro argument Type jsou rovny mocninám čísla 2. Tato vlastnost umožňuje, aby všechny možné množiny hodnot měly odlišný součet, a tak lze podle součtu identifikovat množinu hodnot.
Máme-li tedy nějaký argument, který může nabývat hodnot nějaké množiny vlastností, je vhodné tyto vlastnosti popsat konstantami rovnými mocnině čísla 2.
Konstanty, které lze zadávat do argumentu Type, nejsou pojmenovány. V případě, že bychom s metodou Application.InputBox pracovali často, je vhodné si pojmenované konstanty zavést. Sada takových konstant se nazývá výčtový typ neboli enumeration.
Když je do input boxu zadán jiný typ hodnoty, než povoluje argument Type, input box na to upozorní a nechá uživatete znovu zadat hodnotu.
Když uživatel klikne na tlačítko Cancel, tak je návratová hodnota typu Boolean a je rovna hodnotě False (NEPRAVDA). Tak může programátor detekovat, že bylo stisknuto tlačítko Cancel.
Předávání argumentů mezi procedurami
Procedura může mít jako svůj podprogram jinou proceduru, jiným slovy, procedura může volat jinou proceduru.
Volaná procedura může převzít argumenty od volající procedury.
V prvním příkladu subprocedura Hlavní získá vstupní hodnotu od uživatele a subprocedura Ztrojnásob ji ztrojnásobí.
V tomto příkladu nedochází k opravdovému předávání argumentů subprocedurou Hlavní subproceduře Ztrojnásob. Tyto procedury jen sdílejí společnou globální proměnnou a, která musí být deklarována na začátku modulu.
Option Explicit
Dim a As Integer
Sub Hlavní()
a = Application.InputBox("Zadej číslo:", Type:=1)
Ztrojnásob
MsgBox a, , "Hlavní"
End Sub
Sub Ztrojnásob()
a = a * 3
MsgBox a, , "Ztrojnásob"
End Sub
Volaná procedura může být kdekoli (před i za volající procedurou) ve stejném modulu.
Pokud by se musely ztrojnásobit hodnoty argumentů z více proměnných, musela by mít subprocedura Ztrojnásob pro každou proměnnou svou jinou jinak pojmenovanou kopii. To ukazuje druhý příklad.
Option Explicit
Dim a As Integer, b As Integer
Sub Hlavní()
a = Application.InputBox("Zadej číslo:", Type:=1)
b = Application.InputBox("Zadej číslo:", Type:=1)
Ztrojnásob_a
Ztrojnásob_b
MsgBox "a = " & a & Chr(13) & Chr(10) & "b = " & b, , "Hlavní"
End Sub
Sub Ztrojnásob_a()
a = a * 3
MsgBox a, , "Ztrojnásob_a"
End Sub
Sub Ztrojnásob_b()
b = b * 3
MsgBox b, , "Ztrojnásob_b"
End Sub
Ve třetím příkladu subprocedura Hlavní již skutečně předává argument subproceduře Ztrojnásob.
Subprocedura Ztrojnásob má ve svých závorkách identifikátor x, což způsobí, že již není viditelná v nabídce Makra, protože teď již je spustitelná pouze voláním z jiné procedury.
Option Explicit
Sub Hlavní()
Dim a As Integer, b As Integer
a = Application.InputBox("Zadej číslo:", Type:=1)
b = Application.InputBox("Zadej číslo:", Type:=1)
Ztrojnásob a
Ztrojnásob b
MsgBox "a = " & a & Chr(13) & Chr(10) & "b = " & b, , "Hlavní"
End Sub
Sub Ztrojnásob(x As Integer)
x = x * 3
MsgBox x, , "Ztrojnásob"
End Sub
Čtvrtý příklad se od třetího liší v tom, že při volání subprocedury Ztrojnásob je její argument v závorkách. Kdyby měla subprocedura Ztrojnásob argumentů víc než jeden, nebylo by možné je dát do závorek a řešilo by se to dle šestého příkladu.
V důsledku toho, že je argument v závorce, se konečná hodnota předaných argumentů v subproceduře Ztrojnásob nepředá do subprocedury Hlavní.
Option Explicit
Sub Hlavní()
Dim a As Integer, b As Integer
a = Application.InputBox("Zadej číslo:", Type:=1)
b = Application.InputBox("Zadej číslo:", Type:=1)
Ztrojnásob (a)
Ztrojnásob (b)
MsgBox "a = " & a & Chr(13) & Chr(10) & "b = " & b, , "Hlavní"
End Sub
Sub Ztrojnásob(x As Integer)
x = x * 3
MsgBox x, , "Ztrojnásob"
End Sub
Třetí a čtvrtý příklad se liší způsobem předávání argumentů. Oba dva druhy jejich odlišného chování jsou v některých situacích potřebné.
Ve třetím příkladu došlo k předání argumentů tak, že subprocedura Ztrojnásob dostala ke své práci paměťovou adresu zpracovávaného argumentu a výsledek své činnosti zapsala na tuto adresu. Tento způsob předání argumentů se nazývá předávání argumentů odkazem (by reference).
Ve čtvrtém příkladu došlo k předání argumentů tak, že subprocedura Hlavní zkopírovala předávaný argument a do argumentu x subprocedury Ztrojnásob, která jej zpracovala a po jejím skončení byla jeho konečná hodnota zapomenuta. Tento způsob předání argumentů se nazývá předávání argumentů hodnotou (by value).
Předávání argumentů odkazem je v jazyce VBA implicitní (když se neurčí jinak). Chceme-li předat argumenty hodnotou, můžeme to vyjádřit ještě dle páteho příkladu.
Option Explicit
Sub Hlavní()
Dim a As Integer, b As Integer
a = Application.InputBox("Zadej číslo:", Type:=1)
b = Application.InputBox("Zadej číslo:", Type:=1)
Ztrojnásob a
Ztrojnásob b
MsgBox "a = " & a & Chr(13) & Chr(10) & "b = " & b, , "Hlavní"
End Sub
Sub Ztrojnásob(ByVal x As Integer)
x = x * 3
MsgBox x, , "Ztrojnásob"
End Sub
Někdy je předáváných argumentů víc než jeden a některé se mají předat odkazem a některé hodnotou, viz šestý příklad.
Option Explicit
Sub Hlavní()
Dim a As Integer, b As Integer
a = Application.InputBox("Zadej číslo:", Type:=1)
b = Application.InputBox("Zadej číslo:", Type:=1)
Ztrojnásob a, b
MsgBox "a = " & a & Chr(13) & Chr(10) & "b = " & b, , "Hlavní"
End Sub
Sub Ztrojnásob(ByVal x As Integer, ByRef y As Integer)
x = x * 3
y = y * 3
MsgBox "x = " & x & Chr(13) & Chr(10) & "y = " & y, , "Ztrojnásob"
End Sub
Pole jako argumenty předávané mezi procedurami
Jazyk VBA nedovoluje deklarovat pole jako konstantu, ale je možné využít funkci Array, která přiřadí pole do proměnné typu Variant.
V následujícím příkladu subprocedura PracujSListy vypíše jména listů, zapíše do nich hodnoty z pole, a vybere je. Indexy listů, které se mají zpracovat, a hodnoty, které se mají do listů zapsat, jsou jí předány volající subprocedurou PráceSeSkupinouListů jako pole.
Funkce LBound je použita pro zjištění počátečního indexu pole, což učiní kód nezávislý na možném nastavení číslování indexů pomocí příkazu Option Base na začátku modulu. Kód je tak přenositelný mezi moduly s různým nastavením Option Base.
Option Explicit
Sub PracujSListy(Listy As Variant, Hodnota As Variant)
Dim IndexListu As Byte
Dim ListSešitu As Worksheet
Dim Zpráva As String
Zpráva = ""
IndexListu = LBound(Hodnota)
For Each ListSešitu In Listy
ListSešitu.Cells(1) = Hodnota(IndexListu)
Zpráva = Zpráva & ListSešitu.Name & vbCrLf
IndexListu = IndexListu + 1
Next ListSešitu
MsgBox Zpráva
Listy.Select
End Sub
Sub PráceSeSkupinouListů()
PracujSListy Worksheets(Array(1, 3)), Array(5, 10)
End Sub
Uživatelské formuláře UserForms
Uživatelské formuláře nahrazují dialogové listy starších verzí Excelu. Dají se tvořit i v aplikaci MS Word.
Uživatelský formulář se založí v editoru VBA volbou Insert - UserForm.
Na formulář se přetáhnou ovládací tlačítka (Controls) ze soupravy nástrojů zvané Toolbox. Na tuto soupravu se dají přidávat další nástroje, když se klikne pravým tlačítkem myši na kartu Controls.
K tlačítkům na formuláři se napíše kód obsluhující jejich události. Prostor pro kód se otervře po dvojkliku na ovládací prvek na formuláři. Kód se odkazuje na vlastnosti ovládacích prvků, které mají svůj název a hodnotu v okně vlastností. Po vybrání určitého prvku v okně vlastností klávesa F1 vyvolá nápovědu k dané vlastnosti.
Formulář se spustí pomocí makra napsaného do modulu nebo jako událost listu, sešitu nebo dokumentu:
Sub Ukaž_Formulář()
UserForm1.Show
End Sub
Formulář se skryje ale zůstává v paměti a je možné s ním manipulovat makry pomocí příkazu UserForm1.Hide.
Formulář se odstraní z paměti pomocí příkazu Unload UserForm1, což je stejné, jako když se klikne na standardní tlačítko pro zavření v pravém horním rohu formuláře.
Ovládací tlačítka uživatelských formulářů
 | Label - Popis
Slouží pro zobrazování informací pro uživatele. |
 | TextBox - Textové pole
Slouží pro zadávání informací uživatelem a zobrazování informací, které může uživatel vybrat a kopírovat jinam. |
 | ComboBox - Pole se seznamem
Slouží pro výběr položky ze seznamu a zadání položky uživatelem. |
 | ListBox - Seznam
Slouží pro výběr položky ze seznamu.
Pole se seznamem a Seznam mají vestavěný Posuvník, viz níže, který se na nich objeví, přesáhne-li počet položek hodnotu vlastnosti ListRows. |
 | CheckBox - Zaškrtávací políčko
Slouží pro zadávání informace o hodnotě jeden bit. |
 | OptionButton - Přepínač
Slouží pro výběr položky ze seznamu, neboli jednoho přepínače ze skupiny přepínačů.
Musí se vyskytovat ve skupinách nikoli jednotlivě. Skupiny jsou tvořeny vlastností GroupName nebo jejich umístěním do rámečku. Volně umístěné přepínače se také chovají jako jedna skupina. |
 | Frame - Rámeček
Tvoří skupinu z přepínačů.
Graficky odděluje části formuláře pro jeho lepší přehlednost.
Při tvorbě formuláře umožňuje manipulovat s prvky v něm umístěnými jako s jedním celkem. |
 | ScrollBar - Posuvník
Slouží pro plynulé zadávání hodnot z daného rozpětí. |
 | SpinButton - Číselník
Slouží pro zadávání hodnot z daného rozpětí měněných po určitém kroku, například je tak vhodné realizovat zvýšení ceny o 50 haléřů.
Inkrementace v oboru jiném než celočíselném se však musí odvozovat z celočíselných hodnot, které jediné jsou přípustné pro vlastnost Value prvku Číselník i Posuvník.
Číselník musí být kódem makra propojen s nějakým prvkem zobrazujícím výsledek kliknutí na něj, typicky s Textovým polem. Některé produkty mají tento prvek již v této kombinaci a nazývají jej Spinner. |
 | CommandButton - Příkazové tlačítko
Slouží pro spuštění maker. |
 | ToggleButton - Přepínací tlačítko
Zobrazuje, zda je tlačítko zamáčklé nebo vymáčklé. |
 | TabStrip - Karty
Slouží pro zobrazování datových vět na jednotlivých kartách.
Ovládací prvky se na něj přetáhnou jen jednou a potom se zobrazují na všech kartách stejně.
Musí se k němu napsat kód propojující jej s tabulkou dat. |
 | MultiPage - Vícenásobná stránka
Slouží pro organizaci ovládacích prvků do více stránek, ze kterých si může uživatel vybírat.
Na rozdíl od prvku Karty může být na každé stránce jiný obsah. |
 | Image - Obrázek
Slouží pro zobrazování obrázků. |
 | RefEdit
Tento prvek se musí na soupravu nástrojů přidat dodatečně, viz výše.
Slouží pro zadávání oblastí buněk, se kterými potom mohou pracovat makra. |
Potlačení události Change, která se spustí i změnou hodnoty, ale chceme ji spustit jen editací prvku.
Funkce
Funkce se dělí na
- vestavěné (built-in)
- z jazyka Visual Basic
- funkce listu (Worksheet Functions)
- definované programátorem (User-Defined Functions - UDF)
Vestavěné funkce z jazyka Visual Basic
Excel starší než Excel 5 a jazyk Visual Basic nebyly sloučeny do jazyka VBA. V každém systému byly vyvíjeny jeho vlastní nezávislé funkce, takže některé funkce Excelu (Worksheet Functions) a funkce VBA (z jazyka Visual Basic) se dnes překrývají a mezi některými funkcemi Excelu a VBA jsou konflikty.
Většinou platí pravidlo, že když funkce VBA slouží ke stejnému účelu jako funkce Excelu, potom funkce Excelu není přímo dostupná pro makroprogramování (ale dá se použít pomocí metody Evaluate).
Funkce Excelu MOD a CONCATENATE jsou v jazyce VBA nahrazeny operátory Mod a &.
Abecední seznam funkcí VBA je v nápovědě k Microsoft Visual Basic v nabídce Microsoft Visual Basic Documentation - Visual Basic Language Reference - Functions.
Funkce listu (Worksheet Functions)
Vkládají se do buněk listu pomocí nabídky Vložit funkci.

Mohou se použít i ve vlastních makrech.
Abecední seznam Worksheet Functions je v nápovědě k Microsoft Visual Basic v nabídce Microsoft Excel Visual Basic Reference - Programming Concepts - Events, Worksheet Functions, and Shapes - Using Microsoft Excel Worksheet Functions in Visual Basic - List of Worksheet Functions Available to Visual Basic.
Názvy funkcí listu jsou v nabídce Vložit funkci v češtině, ale v kódu maker musíme používat jejich anglické názvy. Chceme-li vybranou funkci z nabídky Vložit funkci použít v kódu VBA, můžeme si zjistit její název tak, že nahrajeme vložení funkce do buňky a podíváme se na nahraný kód. (Stačí nahrát dvojité kliknutí do buňky s již napsanou funkcí a stisknutí klávesy Enter.)
V prvním příkladu chceme použít funkci VELKÁ, která je v nabídce Vložit funkci v kategorii funkcí Text. Funkce se nahraje jako
ActiveCell.FormulaR1C1 = "=UPPER(RC[-1])"
Název funkce je tedy UPPER. Nejdříve se podíváme do seznamu funkcí VBA v nápovědě. Tam funkce Upper není, ale je tam funkce UCase, která dle nápovědy dělá to, co dělá funkce UPPER. Nahraný název tedy nemusí vždy s hledanou funkcí souhlasit. V seznamu Worksheet Functions funkce UPPER ani funkce UCase není.
Ve druhém příkladu chceme použít funkci PROČISTIT, která je v nabídce Vložit funkci v kategorii funkcí Text. Funkce se nahraje jako
ActiveCell.FormulaR1C1 = "=TRIM(RC[-1])"
Název funkce je tedy TRIM. V seznamu funkcí VBA funkce Trim je, ale odřezává pouze krajní mezery. V seznamu Worksheet Functions funkce Trim také je, a protože je v tomto seznamu, bude mít i stejné chování jako funkce PROČISTIT. Rozdílné chování funkce TRIM můžeme sledovat v tomto makru:
Sub Pročisti()
Dim a As String, b As String
a = " a a "
a = Trim(a)
b = " b b "
b = WorksheetFunction.Trim(b)
End Sub
Chceme-li použít funkci listu, musíme v kódu VBA před ni napsat předponu WorksheetFunction. Funkce listu je metodou objektu WorksheetFunction, který je vlastností objektu Application
Průběžné výsledky můžeme sledovat namísto message boxem pomocí krokování a sledování hodnot proměnných v nabídce Debug v editoru jazyka Visual Basic.

Umístíme kurzor kamkoli do procedury a mačkáme klávesu F8. Umístíme-li kurzor na proměnnou, objeví se její aktuální hodnota.
Funkce definované programátorem (User-Defined Functions - UDF)
Funkce se píší do modulů stejně jako ostatní makra. Nedají se nahrávat. Jejich účelem je vrácení hodnoty.
Je-li v modulu funkce
Function Fahrenheit(Celsius As Double) As Double
Fahrenheit = Celsius * 9 / 5 + 32
End Function
je možné ji použít jako funkci listu z nabídky kategorie funkcí vlastní,

nebo jako podprogram jiné procedury:
Sub CelsiusToFahrenheit()
Dim c As Double
c = Application.InputBox("Zadej stupně Celsia", Type:=1)
MsgBox c & " stupňů Celsia = " & Fahrenheit(c) & " stupňů Fahrenheita."
End Sub
Metoda Volatile
Má-li funkce argument definovaný jako konstantu, zde v buňce A1, tak se po změně hodnoty v buňce A1 nebude přepočítávat.
Function Fahrenheit_A1() As Double
Fahrenheit_A1 = Range("a1") * 9 / 5 + 32
End Function
Přepočítávaní takové funkce lze zajistit přidáním příkazu Application.Volatile na první řádek funkce.
Function Fahrenheit_A1() As Double
Application.Volatile
Fahrenheit_A1 = Range("a1") * 9 / 5 + 32
End Function
Funkce s metodou Application.Volatile se však na rozdíl od normálních funkcí přepočítává po změně každé buňky na listu (nejen jejích vstupních buněk), což může znamenat přílišnou výpočetní zátěž.
Co UDF neumějí
UDF neumí vrátit hodnotu do jiné buňky, než je ta, ve které jsou použity.
UDF neumí naformátovat buňku.
UDF neumí kopírovat a přesouvat buňky.
UDF mohou volat procedury, ale jimi volané sub procedury mají stejná omezení jako výše vyjmenovaná omezení UDF.
UDF jsou pomalejší než vestavěné funkce.
Vybrané typy UDF
Funkce, která prochází oblast
Funkce spočítá, kolikrát se v zadané oblasti buněk vyskytuje zadaný řetězec v buňce.
Tato funkce se dá realizovat lépe maticovým vzorcem =SUMA(KDYŽ(Co=Kde;1)).
Function Kolikrát(Co As String, Kde As Range) As Integer
Dim Buňka As Range
Kolikrát = 0
For Each Buňka In Kde
If Buňka.Value = Co Then Kolikrát = Kolikrát + 1
Next Buňka
End Function
Funkce vracející hodnotu PRAVDA / NEPRAVDA
Function Podmnožina(x As Range, y As Range) As Boolean
Dim BuňkaX As Range, BuňkaY As Range
Podmnožina = False
For Each BuňkaX In x
For Each BuňkaY In y
If BuňkaX = BuňkaY And BuňkaX <> "" Then
Podmnožina = True
Exit Function
End If
Next BuňkaY
Next BuňkaX
End Function
Funkce manipulující s jednotlivými znaky
Přístup k jednotlivým znakům řetězce v Excelu se provádí pomocí funkce Mid.
Function Pozpátku(x As String) As String
Dim i As Integer
Pozpátku = ""
For i = 1 To Len(x)
Pozpátku = Pozpátku & Mid(x, Len(x) - i + 1, 1)
Next i
End Function
Funkce vracející matici
Funke využívá funkci listu MMult. Zadává se jako maticový vzorec.
Funkce vracející matici nebo vektor musí mít návratový typ Variant namísto typu Range.
Function MocninaMatice(x As Range, y As Byte) As Variant
Dim i As Byte
MocninaMatice = x
For i = 1 To y - 1
MocninaMatice = WorksheetFunction.MMult(MocninaMatice, x)
Next i
End Function
Funkce vracející vektor
Funke se zadává jako maticový vzorec do 4 buněk, které musí být vedle sebe (nikoli pod sebou).
Function DnyHodinyMinutySekundy(x As Long) As Variant
Dim b(1 To 4) As Long, SekundVeDni As Long
SekundVeDni = CLng(60) * 60 * 24 '= 86400. Bez CLng (typová konverze) to přeteče.
b(1) = x \ SekundVeDni 'Početní úkony pro každou proměnnou: zpětné lomítko znamená v jazyce VBA opearci DIV (celočíselné dělení bez zbytku).
b(2) = (x - SekundVeDni * b(1)) \ 3600
b(3) = (x - SekundVeDni * b(1) - 3600 * b(2)) \ 60
b(4) = x - SekundVeDni * b(1) - 3600 * b(2) - 60 * b(3)
DnyHodinyMinutySekundy = b
End Function
Funkce volající jinou funkci
Funke má jako vstup i výstup datum, který je číslem, které je vhodné v buňce naformátovat jako datum.
Pokud by v závorce s argumenty nebyl uveden způsob předání argumentů ByVal (hodnotou), byl by argument předán odkazem a funkce ZaKolikDníJeNejbližšíPátek13 by vrátila výsledek 0.
Function NejbližšíPátek13(ByVal Datum As Date) As Date 'Pokud není uvedeno ByVal, je předáváno jako ByRef.
While Not (Day(Datum) = 13 And Weekday(Datum) = vbFriday)
Datum = Datum + 1
Wend
NejbližšíPátek13 = Datum
End Function
Funke má jako vstup datum, který je číslem, které je vhodné v buňce naformátovat jako datum, a jako výstup Integer.
Function ZaKolikDníJeNejbližšíPátek13(Datum As Date) As Integer
Dim DatumNejbližšíhoPátku13 As Date
DatumNejbližšíhoPátku13 = NejbližšíPátek13(Datum) 'Volání předchozí funkce
ZaKolikDníJeNejbližšíPátek13 = DatumNejbližšíhoPátku13 - Datum
End Function
Zachytávání běhových chyb
Při běhu programu může dojít k běhovým chybám (run time errors).
Například metoda Application.InputBox končí běhovou chybou, když je požadovaným typem vstupu buněčná oblast (A cell reference, as a Range object), a uživatel klikne na tlačítko Cancel.
Vzhledem k tomu, že programy musí být schopny zpracovat předem neznámá vstupní data, mají programovací jazyky (zvláště ty modernější zaměřené na vývoj interaktivních aplikací) mechanismy pro zachytávání běhových chyb.
Běhová chyba způsobí ukončení programu a vyvolá message box informující o druhu chyby. Zachycení běhové chyby namísto toho umožní, aby program pokračoval.
V prvním příkladu je k zachycení chyby použit příkaz On Error Resume Next.
Sub MakroChyba1()
Dim Oblast As Range
Dim a As Integer, b As Integer
On Error Resume Next
Set Oblast = Application.InputBox("Vyber buněčnou oblast:", Type:=8)
If Oblast Is Nothing Then MsgBox "Nebyla vybána buněčná oblast." Else Oblast.Select
a = Application.InputBox("Zadej čitatel:", Type:=1)
b = Application.InputBox("Zadej jmenovatel různý od 0:", Type:=1)
MsgBox a & " / " & b & " = " & a / b
End Sub
Pokud nějaký příkaz následující kdekoli za příkazem On Error Resume Next způsobí běhovou chybu, program pokračuje v chodu od následujícího příkazu.
Druhý příklad ukazuje, jak se zachytávání chyb vypíná příkazem On Error GoTo 0.
Sub MakroChyba2()
Dim Oblast As Range
Dim a As Integer, b As Integer
On Error Resume Next
Set Oblast = Application.InputBox("Vyber buněčnou oblast:", Type:=8)
If Oblast Is Nothing Then MsgBox "Nebyla vybána buněčná oblast." Else Oblast.Select
On Error GoTo 0
a = Application.InputBox("Zadej čitatel:", Type:=1)
b = Application.InputBox("Zadej jmenovatel různý od 0:", Type:=1)
MsgBox a & " / " & b & " = " & a / b
End Sub
Zachytávání chyb by mělo být zapnuto pouze v problémových částech kódu. Jinak se může stát, že nebudou odhaleny sémantické chyby, které lze řešit.
Druhý příklad má správně zapnuté zachytávání chyb jen pro zadávání buněčné oblasti a povede k běhové chybě, když uživatel zadá do proměnné b hodnotu 0.
Ve třetím příkladu je tato běhová chyba správně ošetřena jiným způsobem než příkazem On Error Resume Next.
Sub MakroChyba3()
Dim Oblast As Range
Dim a As Integer, b As Integer
On Error Resume Next
Set Oblast = Application.InputBox("Vyber buněčnou oblast:", Type:=8)
If Oblast Is Nothing Then MsgBox "Nebyla vybána buněčná oblast." Else Oblast.Select
On Error GoTo 0
a = Application.InputBox("Zadej čitatel:", Type:=1)
Do
b = Application.InputBox("Zadej jmenovatel různý od 0:", Type:=1)
Loop Until b <> 0
MsgBox a & " / " & b & " = " & a / b
End Sub
Příkaz On Error Resume Next se používá v případě, že příkaz, ve kterém nastala běhová chyba, chceme pouze přeskočit a pokračovat následujícím příkazem. Někdy však potřebujeme běhovou chybu ošetřit větším množstvím příkazů. Potom potřebujeme vytvořit větev programu, která se provede jen v případě běhové chyby. Vstup do této větve programu se obvykle provádí pomocí návěští (label)
Čtvrtý příklad ukazuje ošetření chyby kódem, na který se odkazuje příkaz On Error GoTo ErrorHandler. ErrorHandler je název návěští. Není to součást jazyka VBA, proto může být i jiný. ErrorHandler nebo ErrHandler jsou obvyklé názvy.
Sub MakroChyba4()
Dim Oblast As Range
Dim a As Integer, b As Integer
On Error GoTo ErrorHandler
Set Oblast = Application.InputBox("Vyber buněčnou oblast:", Type:=8)
On Error GoTo 0
Oblast.Select
a = Application.InputBox("Zadej čitatel:", Type:=1)
Do
b = Application.InputBox("Zadej jmenovatel různý od 0:", Type:=1)
Loop Until b <> 0
MsgBox a & " / " & b & " = " & a / b
Exit Sub
ErrorHandler:
MsgBox "Nebyla vybána buněčná oblast." & Chr(13) & Chr(10) & "Bude vybána buněčná oblast automaticky."
Set Oblast = Range("a1:b2")
Resume Next
End Sub
Dojde-li v příkazu Set Oblast = Application.InputBox("Vyber buněčnou oblast:", Type:=8) k běhové chybě, vykonávání kódu se přesune na návěští ErrorHandler:
Příkaz Resume Next přesune vykonávání kódu na příkaz On Error GoTo 0, tedy na následující příkaz po příkazu s běhovou chybou.
Příkaz Exit Sub musí být před blokem s kódem pro ošetřování chyb, aby se tento kód prováděl jen v případě, že k běhové chybě dojde.
Zároveň musí být blok s kódem pro ošetřování chyb vždy na konci procedury.
Pátý příklad ukazuje alternativní řešení čtvrtého příkladu. To, že došlo k běhové chybě, se zjistí podle vlastnosti Number objektu Err a do větve programu s kódem ošetřujícím běhovou chybu se vstoupí pomocí řídící struktury If...Then.
Sub MakroChyba5()
Dim Oblast As Range
Dim a As Integer, b As Integer
On Error Resume Next
Set Oblast = Application.InputBox("Vyber buněčnou oblast:", Type:=8)
If Err.Number <> 0 Then
MsgBox "Nebyla vybána buněčná oblast." & Chr(13) & Chr(10) & "Bude vybána buněčná oblast automaticky."
Set Oblast = Range("a1:b2")
End If
On Error GoTo 0
Oblast.Select
a = Application.InputBox("Zadej čitatel:", Type:=1)
Do
b = Application.InputBox("Zadej jmenovatel různý od 0:", Type:=1)
Loop Until b <> 0
MsgBox a & " / " & b & " = " & a / b
End Sub
Příkaz On Error GoTo 0 a dle nápovědy i Resume Next, Exit Sub, Exit Function a Exit Property nastaví hodnotu vlastnosti Number objektu Err na nulu, což lze udělat i příkazem Err.Clear.
Podle hodnoty Err.Number lze také kód pro ošetřování běhových chyb větvit pro různé druhy chyb pomocí řídící struktury If...Then...Else nebo Select Case.
Následující kód lze přiřadit tlačítku na formuláři typu UserForm, které po kliknutí na něj posune vybranou oblast na listu i s formátováním o řádek nahoru.
Option Explicit
Private Sub CommandButton1_Click()
Dim Oblast As Range
Dim List As Worksheet
On Error Resume Next 'Můžeme zapomenout vybrat oblast.
Set Oblast = Range(RefEdit1.Value)
On Error GoTo 0
If Oblast Is Nothing Then
MsgBox "Musíte vybrat oblast!"
Else
Set list = Oblast.Worksheet
List.Activate 'Musíme vybrat list, abychom na něm mohli použít metodu Select.
Oblast.Cut
On Error Resume Next 'Můžeme se posunout za okraj listu.
Oblast.Offset(-1, 0).Select
If Err.Number = 0 Then
ActiveSheet.Paste
RefEdit1.Value = Selection.Address
End If
On Error GoTo 0
End If
End Sub
Zachytávání běhových chyb v UDF
Funkce listu vracejí do buněk chybové hodnoty #DIV/0!, #N/A, #NAME?, #NULL!, #NUM!, #REF!, #VALUE!, když mají chybný vstup. UDF, pokud nejsou speciálně napsány, vracejí s chybným vstupem do buněk jen hodnotu #VALUE!, ale horší je, že nemohou být volány jiným makrem (namísto použití v buňkách), protože potom při jejich vykonávání dojde k běhové chybě. Způsob, jak napsat UDF s ošetřením chyb, je v následujícím příkladu.
Function MojeDěleníNeošetřené(Čitatel As Double, Jmenovatel As Double) As Double
MojeDěleníNeošetřené = Čitatel / Jmenovatel
End Function
Function MojeDěleníOšetřené(Čitatel As Double, Jmenovatel As Double) As Variant 'Funkce vracející též chybovou hodnotu musí mít návratový typ Variant.
'MojeDěleníOšetřené = IIf(Jmenovatel = 0, CVErr(xlErrDiv0), Čitatel / Jmenovatel) 'Funkci IIf nelze použít, protože dle nápovědy vyhodnocuje vždy všechny 3 své části.
If Jmenovatel = 0 Then MojeDěleníOšetřené = CVErr(xlErrDiv0) Else MojeDěleníOšetřené = Čitatel / Jmenovatel
End Function
Sub TestChyby()
Dim a As Variant
'If IsError(MojeDěleníNeošetřené(3, 0)) Then If CVErr(MojeDěleníNeošetřené(3, 0)) = CVErr(xlErrValue) Then MsgBox "Chyba!" 'Volání funkce s neošetřenou chybou skončí běhovou chybou při vykonávání funkce.
'Výsledek funkce CVErr se musí porovnávat s chybou, jinak nastane chyba typu Type mismatch, proto se musí porovnávaná hodnota předem otestovat na chybu funkcí IsError.
If IsError(Range("a1")) Then MsgBox "Nějaká chyba v buňce!"
If IsError(Range("a1")) Then If Range("a1") = CVErr(xlErrValue) Then MsgBox "Chyba!" 'V buňce A1 je vzorec "=MojeDěleníNeošetřené(3;0)"
If IsError(Range("a2")) Then If Range("a2") = CVErr(xlErrDiv0) Then MsgBox "Dělení nulou!" 'V buňce A2 je vzorec "=MojeDěleníOšetřené(3;0)"
If IsError(MojeDěleníOšetřené(3, 0)) Then MsgBox "Nějaká chyba ve volané funkci!"
If IsError(MojeDěleníOšetřené(3, 0)) Then If MojeDěleníOšetřené(3, 0) = CVErr(xlErrDiv0) Then MsgBox "Dělení nulou!"
a = MojeDěleníOšetřené(3, 0) 'Lepší než předchozí řádek.
If IsError(a) Then If a = CVErr(xlErrDiv0) Then MsgBox "Dělení nulou!"
End Sub
Sub TestChybyVBuňce()
Dim HodnotaVBuňce As Variant
HodnotaVBuňce = ActiveCell.Value
If IsError(HodnotaVBuňce) Then
Select Case HodnotaVBuňce
Case CVErr(xlErrDiv0): MsgBox "Dělení nulou!"
Case CVErr(xlErrNA): MsgBox "Nedostupná hodnota!" 'Například chyba funkce SVYHLEDAT
Case CVErr(xlErrName): MsgBox "Chyba ve jménu funkce nebo argumentu!"
Case CVErr(xlErrNull): MsgBox "Chybně zadaná oblast!" 'http://spreadsheets.about.com/od/formulatips/qt/null_error.htm
Case CVErr(xlErrNum): MsgBox "Výsledek přetekl!" 'http://www.databison.com/index.php/excel-na-ref-name-div0-null-value-num-error/
Case CVErr(xlErrRef): MsgBox "Oblast v odkazu byla vymazána!" 'http://spreadsheets.about.com/od/formulatips/qt/REF_error.htm
Case CVErr(xlErrValue): MsgBox "Chybná hodnota!"
Case Else: MsgBox "Jiná chyba!"
End Select
Else: MsgBox "Ve vybrané buňce není chyba."
End If
End Sub
Excel označuje buňky s možnou chybovou hodnotou malým zeleným trojůhelníčkem v jejich horním levém rohu. U vybrané buňky s chybovou hodnotou je tlačítko
s dalšími informacemi o chybě. Buňku lze testovat na určitý typ chyby kódem
If Range("a1").Errors.Item(xlEvaluateToError).Value = True Then MsgBox "Chybová hodnota!"
Buňka obsahuje objekt Errors, což je kolekce možných chyb, neboť v jedné buňce může být víc chyb (například zároveň chybová hodnota a vzorec odlišný od ostatních vzroců ve sloupci). Je nutné testovat jednotlivě, zda buňka obsahuje určitou chybu z množiny možných chyb, tak že právě testovanou chybu označíme vestavěnou konstantou výčtového typu xlErrorChecks. Následující kód vypíše všechny chyby v aktivní buňce.
Sub TestováníChyb()
Dim Zpráva As String
Zpráva = ""
If ActiveCell.Errors.Item(xlEvaluateToError).Value = True Then Zpráva = Zpráva & "The cell evaluates to an error value. - Chybová hodnota!" & vbCrLf
If ActiveCell.Errors.Item(xlTextDate).Value = True Then Zpráva = Zpráva & "Date entered as text." & vbCrLf
If ActiveCell.Errors.Item(xlNumberAsText).Value = True Then Zpráva = Zpráva & "Number entered as text." & vbCrLf
If ActiveCell.Errors.Item(xlInconsistentFormula).Value = True Then Zpráva = Zpráva & "The cell contains an inconsistent formula for a region. - Nekonzistentní vzorec v oblasti!" & vbCrLf
If ActiveCell.Errors.Item(xlOmittedCells).Value = True Then Zpráva = Zpráva & "Cells omitted. - Vzorec odkazuje na oblast, s níž sousedí další čísla." & vbCrLf
If ActiveCell.Errors.Item(xlUnlockedFormulaCells).Value = True Then Zpráva = Zpráva & "Formula cells are unlocked. - Buňka se vzorcem je odemčená." & vbCrLf
If ActiveCell.Errors.Item(xlEmptyCellReferences).Value = True Then Zpráva = Zpráva & "The cell contains a formula referring to empty cells. - Odkaz na prázdnou buňku!" & vbCrLf
If ActiveCell.Errors.Item(xlListDataValidation).Value = True Then Zpráva = Zpráva & "Data in the list contains a validation error. - Ověřovaná buňka není v seznamu" & vbCrLf
If ActiveCell.Errors.Item(xlInconsistentListFormula).Value = True Then Zpráva = Zpráva & "The cell contains an inconsistent formula for a list. - Nekonzistentní vzorec v seznamu!" & vbCrLf 'Od verze 2007.
MsgBox Zpráva
End Sub
Jak udělat chyby v buňce
xlErrorChecks | Co vyvolá chybu |
xlEvaluateToError | Chybová hodnota všech možných druhů dle funkce CVErr |
xlTextDate | Do buňky A1 napíšeme datum. Do jiné buňky napíšeme funkci =HODNOTA.NA.TEXT(A1;"d.m.rr"). Podstatné je, že formát musí mít dvoučíslicový rok, tedy ne například obvyklejší "d.m.rrrr". Buňku s funkcí zkopírujeme do jiné buňky pomocí volby Vložit jinak - Hodnoty Výsledná hodnota má tuto chybu. Chyba může být i výsledkem importu z různých databází, proto je užitečné vědět, jak ji odstranit.
Odstranění chyby v buňceDo jiné buňky napíšeme číslo 1. Zkopírujeme tuto buňku do schránky pomocí Ctrl+C. Vybereme oblast, ve které jsou všechny nebo některé buňky vložené jako text a měly být vloženy jako datum nebo číslo. Do vybrané oblasti vložíme obsah schránky pomocí volby Vložit jinak - Násobit Stejně funguje i číslo 0 a Vložit jinak - Přičíst Po této operaci se buňka s datumem naformátuje jako číslo, což opravíme tak, že ji naformátujeme jako datum. |
xlNumberAsText | Do buňky A1 napíšeme číslo. Do jiné buňky napíšeme funkci =ZAOKROUHLIT.NA.TEXT(A1). Buňku s funkcí zkopírujeme do jiné buňky pomocí volby Vložit jinak - Hodnoty Výsledná hodnota má tuto chybu a odstranění této chyby je stejné jako u výše popsané chyby xlTextDate. |
xlInconsistentFormula | V tabulce je sloupec s funkcí, která se do všech řádků obvykle zadává roztažením z první buňky. Pokud se do nějaké buňky vzorec napíše jinak než do okolních buněk, vznikne tato chyba. |
xlOmittedCells | Do oblasti A1:A4 napíšeme nějaká čísla. Do buňky A5 vložíme funkci =SUMA(A2:A3). |
xlUnlockedFormulaCells | Buňku s nějakým vzorcem odemkneme pomocí volby Formát buněk - Zámek - odškrtnout Uzamčeno. Všechny buňky jsou implicitně uzamčené, což se projeví po zamknutí listu. Před zamknutím listu lze některé buňky odemknout, aby do nich mohl uživatel vkládat hodnoty. Z vložených hodnot něco mohou počítat vzorce, které jsou v uzamčených buňkách. Uzamčení brání změně vzorce, ale dovoluje změnu výsledné hodnoty vzorce. |
xlEmptyCellReferences | V buňce je vzorec, který se odkazuje na jinou buňku, která není vyplněná. Na kartě Kontrola chyb bývá indikátor této chyby implicitně vypnutý, takže by chybu odhalilo pouze výše uvedené makro TestováníChyb |
xlListDataValidation | Do jednoho sloupečku buněk zapíšeme nějaké hodnoty, například druhy ovoce. Do druhého sloupečku, který nemusí být vedle prvního, napíšeme každý druh ovoce jen jednou. Na první sloupeček nastavíme ověření dat pomocí seznamu, kterým je druhý sloupeček. Pokud jsou v prvním sloupečku hodnoty, které nejsou ve druhém sloupečku, tak se to projeví, až když první sloupeček převedeme na seznam pomocí volby Vložení - Tabulka (ve starších verzích Data - Seznam). |
xlInconsistentListFormula | Vytvoříme tabulku se sloupečkem s konzistentní funkcí. Tabulku převedeme na seznam pomocí volby Vložení - Tabulka (ve starších verzích Data - Seznam). Ve sloupečku s funkcí změníme jednu funkci. Chyba nebude indikována, když nejdříve vytvoříme nekonzistentní funkci a potom teprv převedeme tabulku na seznam. Tato chyba je novinkou od verze MS Excel 2007. |
Buňky v Excelu
Buněčné oblasti jsou reprezentovány objektem Range.
Range je zároveň vlastnost objektu Application, která se odkazuje na objekt Range.
Metoda Activate a Select
Jedny z nejdůležitějších metod objektu Range jsou Activate a Select.
Metodou Select lze vybrat oblast buněk. V rámci oblasti buněk je vždy jedna buňka aktivní a dá se měnit pomocí metoty Activate.
Tyto metody lze použít pouze na aktivním listu.
Po zavolání metody Select se mění objekt Selection.
Efektivnější jsou makra, která metody Activate a Select nepotřebují, například příkaz Worksheets(3).Range("a3") = 3
Styl A1
Vyzkoušejte si následující příkazy:
Range("a3").Select
Range("a1:b2").Select
Range("a1:a2,c1:c2,e1:e2").Select
Range("a1,e2").Select
Range("a1", "e2").Select
Range("MojeData").Select 'Funguje za předpokladu, že byl definován název "MojeData" pro nějakou oblast.
Range("a1", Selection).Select 'Projeví se, když je před tím vybrána jiná buňka než A1. Vlastnost Range zde má argument Selection, což je objekt.
Range(Range("a1"), Range("e2")).Select 'Druhý příklad využití objektu Range jako argumentu vlastnosti Range
Je možný i zkrácený styl odkazování:
[a3].Select
[a1:b2].Select
[a1:a2,c1:c2,e1:e2].Select
[a1,e2].Select
[MojeData].Select
Zkrácený styl odkazování využívá metodu Evaluate objektu Application. Je to méně flexibilní způsob odkazování než pomocí vlastnosti Range, protože neumožňuje odkazovat se pomocí textových řetězců Range("a3")
které mohou být výsledkem výpočtu
I = 3
Řetězec = "a" & I
Range(Řetězec).Select
a objektů Range("a1", Selection)
Styl umožňující indexování čísly
Objekty Application, Worksheet a Range mají vlastnost Cells, která umožňuje adresovat buňky těchto objektů.
Vlastnost Cells může mít 1 nebo 2 argumenty.
V případě 1 argumentu se buňky adresují jedna po druhé v pořadí, v jakém se vybírají mačkáním tabelátoru ve vybrané oblasti (což je ekvivalentní metodě Activate).
Range("a1:b3").Cells(3).Activate
V případě 2 argumentů se buňky adresují pomocí pořadí řádku (1. argument) a sloupku (2. argument). Takže následující příklad aktivuje stejnou buňku jako předcházející příklad.
Range("a1:b3").Cells(2, 1).Activate
Na první (horní levou) buňku v oblasti se odkazujeme jako na Cells(1) nebo Cells(1, 1).
Jsou možné i takové indexy (argumenty) vlastnosti Cells, které překročí výchozí oblast, jsou možné i nulové a záporné indexy, pokud nepřekročí hranici listu.
V předchozích dvou příkladech byla adresována jednotlivá buňka v rámci objektu Range. Adresujeme-li jednotlivou buňku v rámci objektu Worksheet, můžeme to udělat následujícími způsoby, kdy v obou příkladech docílíme výběru buňky B2 na aktivním listu.
Cells(2, 2).Select
Cells(2, "B").Select
Chceme-li například vybrat oblast s adresou "a1:b3" a potřebujeme tuto adresu vypočíst z indexů levé horní a pravé dolní buňky, použijeme vlastnost Cells následujícím způsobem:
Range(Cells(1, 1), Cells(3, 2)).Select
Tento příklad však funguje pouze na aktivním listu.
Chceme-li manipulovat s buňkami na neaktivním listu, povede následující kód k chybě,
Worksheets(3).Range(Cells(1, 1), Cells(3, 2)) = "vyplněno"
protože adresujeme objekt Range objektu Worksheets(3) pomocí vlastnosti Cells, která je zde vlastností objektu Application, což znamená, že je to vlastnost aktivního listu.
Správný kód je
Worksheets(3).Range(Worksheets(3).Cells(1, 1), Worksheets(3).Cells(3, 2)) = "vyplněno"
Ještě lepší je použít v tomto kódu konstrukt With...End With. Výsledkem je přehlednější kód, který bude navíc efektivněji vykonáván.
With Worksheets(3)
.Range(.Cells(1, 1), .Cells(3, 2)) = "vyplněno"
End With
Tečky uvnitř konstruktu With...End With musí být před každým objektem, metodou nebo vlastností, která patří objektu za slovem With.
Vlastnosti Rows a Columns
Objekty Application, Worksheet a Range mají vlastnosti Rows a Columns, které umožňují adresovat řádky a sloupky buněk těchto objektů.
Následující marko postupně vybere všechny řádky předem vybrané oblasti a zobrazí v message boxu součet pro právě vybraný řádek.
Sub SumyŘádků()
Dim Oblast As Range, Řádek As Range
Set Oblast = Selection
For Each Řádek In Oblast.Rows
Řádek.Select
MsgBox WorksheetFunction.Sum(Řádek)
Next Řádek
Oblast.Select
End Sub
Vlastnost Offset objektu Range
Vlastnost Offset objektu Range se odkazuje na stejně velkou oblast, která je o určitý počet řádků a sloupků oproti objektu Range posunutá.
Vyzkoušejte si následující příkazy:
Selection.Offset(0, 0).Select
Selection.Offset(1, 1).Select
Selection.Offset(-1, -1).Select
Vlastnost Resize objektu Range
Vlastnost Offset objektu Range se odkazuje na oblast, jejíž horní levý roh je stejný jako u objektu Range a počet řádků a sloupků je určena argumenty vlastnosti Resize.
Selection.Resize(5, 4).Select
Selection.Resize(, 4).Select
Když se vynechá první nebo druhý argument, bude zachován původní počet řádků nebo sloupků.
Následující kód předefinuje oblast "MojeData" tak, že bude dole delší o jeden řádek. Takový kód by se mohl vykonat vždy, když se do dané tabulky přidá další řádek.
Const Názevoblasti As String = "MojeData"
With Range(Názevoblasti)
.Resize(.Rows.Count + 1).Name = Názevoblasti
End With
Vlastnost CurrentRegion
Vlastnost CurrentRegion rozšíří aktuální výběr na všechny přilehlé buňky. Pokud například máme pevně danou polohu záhlaví tabulky, tak můžeme napsat příkaz pro výběr záhlaví tabulky a potom příkaz Selection.CurrentRegion.Select vybere celou tabulku podle její aktuální velikosti.
Vlastnost CurrentRegion se dá zjistit nahráním akce, kdy se klávesou F5 zobrazí dialog Přejít na, klikne se v něm na tlačítko Jinak... a v novém dialogu se vybere Aktuální oblast.
Dialog Přejít na - Jinak...
Pomocí dialogu Přejít na - Jinak... je možné vybrat různé druhy buněk a příslušný kód VBA zjistit nahráním této akce. Všechny možnosti tohoto dialogu jsou vysvětleny v souboru Excel Asistent Magazín 02/2003 na stránkách http://www.dataspectrum.cz/excelmag/excelmagmain.htm.
Vlastnost End
Vlastnost End emuluje operaci Ctrl+kurzorová klávesa (případně kurzorová klávesa v režimu END).
Začíná-li buňkou A1 tabulka, následující kód vybere první buňku posledního řádku této tabulky.
Range("A1").End(xlDown).Select
Je-li v horní části listu tabulka s prázdnými řádky, můžeme se dostat na konec této tabulky pomocí následujícího kódu.
Cells(Rows.Count, "A").End(xlUp).Select
Začíná-li buňkou A1 tabulka, následující kód vybere první sloupec této tabulky.
With Range("A1")
Range(.Cells(1), .End(xlDown)).Select
End With
Stejnou akci provede kód Range("A1").CurrentRegion.Columns(1).Select
Začíná-li na prvním listu v sešitu buňkou A1 tabulka, následující kód zkopíruje záhlaví této tabulky i s formátováním na druhý list.
With Worksheets(1).Range("A1")
.Range(.Cells(1), .End(xlToRight)).Copy Destination:=Worksheets(2).Range("A1")
End With
Doplnění součtů do tabulky
Následující makro předpokládá, že máme vybranou alespoň jednu buňku tabulky, která má nadpisy řádků a sloupků.
Sub SumyŘádků()
Set PočátečníVýběr = Selection 'Zapamatujeme si počáteční výběr.
Selection.CurrentRegion.Select 'Vybereme celou tabulku
With Selection 'Vybereme data v tabulce.
Selection.Offset(1, 1).Resize(.Rows.Count - 1, .Columns.Count - 1).Select
End With
Set Data = Selection 'Oblast s daty uložíme do proměnné Data.
With Selection 'Vybereme horní buňku, do které se má doplnit součet.
.Cells(1, .Columns.Count + 1).Select
End With
Selection.Formula = "=sum(" & Data.Rows(1).Address(0, 0) & ")"
With Selection 'Zkopírujeme obsah horní buňky se součtem do buněk pod ní.
.Copy Destination:=.Offset(1, 0).Resize(Data.Rows.Count - 1)
End With
PočátečníVýběr.Select 'Přesuneme se na počáteční výběr.
End Sub
Vzorce
Sumy se doplní jako vzorec.
V české verzi Excelu je v prvním řádku tabulky například vzorec =SUMA(B2:C2).
Nahrajeme-li vložení vzorce SUMA do buňky, zjistíme, že jeho anglický název je SUM a v nápovědě zjistíme, že je dostupný jako metoda Sum objektu WorksheetFunction.
Chceme-li vložit funkci listu do buňky, určí se funkce jako hodnota vlastnosti Formula objektu Range.
Je-li v buňce vzorec, potom její vlastnost Formula má hodnotu textového řetězce, který vzorec generuje.
Chceme-li vložit do buňky vzorec makrem, musíme jako hodnotu její vlastnosti Formula sestavit příslušný textový řetězec.
První část řetězce je rovna "=sum(".
Potom následuje adresa oblasti, která má být sečtena, tedy B2:C2.
Tuto adresu oblasti je vhodné zjistit jako vlastnost Address objektu Range("B2:C2"), na který se můžeme odkázat pomocí vlastností Cells, Rows nebo Columns nějakého jiného objektu Range.
První 2 argumenty vlastnosti Address, RowAbsolute a ColumnAbsolute, říkají, zda má být adresa vrácena s absolutním nebo relativním odkazem na řádek nebo sloupek. Jejich implicitní hodnota je True, takže relativní adresu musíme zadat jako Address(rowabsolute:=False, columnabsolute:=False) nebo Address(0, 0).
Poslední částí vzorce je ukončující závorka, tedy ")".
Části vzorce se zřetězí operátorem &.
Celý vzorec jako hodnota vlastnosti Formula je tedy "=sum(" & Data.Rows(1).Address(0, 0) & ")".
Někdy, je výhodnější odkazovat se na oblast argumentu vzorce ve formě počtu řádků a sloupců, o které je tato oblast posunutá vůči buňce se vzorcem. V takovém případě se používá místo vlastnosti Formula vlastnost FormulaR1C1. V této podobě nahrává zadávání vzorců do buněk makrorekordér. Převod mezi oběma způsoby zápisu vzorců se provádí metodou Application.ConvertFormula.
Prázdné buňky
Prázdná buňka buďto neobsahuje nic nebo obsahuje vzorec, který vrací prázdný řetězec.
Hodnota IsEmpty(ActiveCell) je True jen pro buňky, ve kterých nic není.
Hodnota ActiveCell.Value = "" je True pro buňky, ve kterých nic není, a pro buňky se vzorcem, který vrací prázdný řetězec.
Pokud v buňce není konstanta nebo vzorec, ale je naformátována, dá se detekovat pomocí metody SpecialCells(xlCellTypeLastCell) objektu Range nebo vlastnosti UsedRange objektu Worksheet.
Metoda SpecialCells(xlCellTypeLastCell) se dá zjistit nahráním akce, kdy se klávesou F5 zobrazí dialog Přejít na, klikne se v něm na tlačítko Jinak... a v novém dialogu se vybere Poslední buňka.
Příkaz ActiveSheet.UsedRange.Select
vybere nejmenší obdélník, do kterého se vejdou všechny použité buňky (s hodnotou nebo naformátované).
Příkaz ActiveCell.SpecialCells(xlCellTypeLastCell).Select
vybere pravou dolní buňku tohoto obdélníku.
Pokud buňky, které ovlivňují oblast UsedRange, vymažeme, metoda SpecialCells(xlCellTypeLastCell) bezprostředně potom zavolaná tuto změnu nezachytí. Informace o aktuálním stavu se aktualizuje voláním vlastnosti UsedRange nebo uložením sešitu.
3 způsoby, jak vybrat následující řádek pod tabulkou
Následujcí makra se hodí v úlohách, ve kterých je třeba přidávat data do tabulky.
Všechna makra předpokládají výchozí stav, kdy je vybrána celá tabulka. Pokud má tabulka záhlaví v buňce A1, potom příkaz Range("A1").CurrentRegion.Select vybere celou tabulku.
Offset a Rows.Count
Selection.Offset(1, 0).Rows(Selection.Rows.Count).Select
End, Columns.Count, Offset a Resize
Příkazy
PočetSloupků = Selection.Columns.Count
Selection.End(xlDown).Select
Selection.Offset(1, 0).Select
Selection.Resize(1, PočetSloupků).Select
je možné sloučit do jediného:
With Selection
.End(xlDown).Offset(1, 0).Resize(1, .Columns.Count).Select
End With
IsEmpty, Columns.Count, Offset a Resize
PočetSloupků = Selection.Columns.Count
With Selection
Do Until IsEmpty(ActiveCell)
ActiveCell.Offset(1, 0).Activate
Loop
End With
Selection.Resize(1, PočetSloupků).Select
Přenos hodnot mezi datovou strukturou pole a oblastí buněk
Problematika přenosu hodnot mezi datovou strukturou pole a oblastí buněk je ukázána na problému vymazání určitých řádků z tabulky.
Tabulka, na které fungují následující makra, má jako první řádek záhlaví, které se nikdy nemaže, a ve čtvrtém sloupku má v řádcích, které mají být vymazány, slovo "Vymazat".
Makra pro vymazání řádků se snaží být co nejohleduplnější k případnému obsahu umístěnému vedle nebo pod tabulku, což znamená, že tento obsah nebude vymazán nebo posunut, protože makra neodstraňují celé řádky.
První makro nevyužívá přenos hodnot mezi datovou strukturou pole a oblastí buněk.
V cyklu For Each Řádek In Selection.Rows se vymažou řádky označené slovem "Vymazat".
Nebyl-li označen žádný řádek nebo byly označeny úplně všechny, je úkol hotov.
V ostatních případech se nevymazané řádky tabulky přesunou pomocí příkazů Cut (Vyjmout) a Paste (Vložit) postupně od konce tabulky směrem k záhlaví tak, aby mezi nimi nebyly prázdné řádky.
Sub PromazáníTabulky()
Const Vymazat As String = "Vymazat"
Const PořadíSloupkuVymazat As Integer = 4
Dim Řádek As Range
Dim AdresaPrvníBuňky As String
Dim PočetDatovýchŘádků As Integer
Dim PočetVymazanýchŘádků As Integer
Dim Hotovo As Boolean
Selection.CurrentRegion.Select
PočetDatovýchŘádků = Selection.Rows.Count - 1
AdresaPrvníBuňky = Selection.Cells(1).Address
PočetVymazanýchŘádků = 0
Hotovo = False
For Each Řádek In Selection.Rows
Řádek.Select
If Selection.Cells(PořadíSloupkuVymazat) = Vymazat Then
Selection.ClearContents
PočetVymazanýchŘádků = PočetVymazanýchŘádků + 1
End If
Next Řádek
If PočetVymazanýchŘádků > 0 And PočetVymazanýchŘádků < PočetDatovýchŘádků Then
Do
Selection.CurrentRegion.Select
Selection.Cut
Selection.End(xlUp).Select
Hotovo = Selection.Address = AdresaPrvníBuňky
Selection.Offset(1, 0).Select
ActiveSheet.Paste
Loop Until Hotovo
Selection.Cut
Selection.Offset(-1, 0).Select
ActiveSheet.Paste
End If
End Sub
Byla by možná jednodušší varianta makra, které by odstraňovalo celé řádky, a aby nepoškodilo obsah vedle a pod tabulkou, tak by tabulku vložilo na nově vložený list, tam by provedlo odstranění celých řádků, vymazalo by původní tabulku na původním listu, výslednou tabulku by z nového listu zkopírovalo na původní list a odstranilo by nový list.
Motivací pro makra, která přenášejí hodnoty mezi datovou strukturou pole a oblastí buněk, je zrychlení zpracování. Odstraňování řádků z velmi velkých tabulek by mohlo mít měřitelný rozdíl v rychlosti maker výše uvedeného typu oproti makrům níže uvedeného typu.
Makro příkazem Data = Selection uloží do proměnné Data všechny datové řádky tabulky (tedy vše kromě záhlaví). Tímto příkazem se z proměnné Data stane dvourozměrné pole s hodnotami z tabulky. První rozměr reprezentuje počet řádků a druhý rozměr reprezentuje počet sloupků, takže je možné přistupovat k jednotlivým hodnotám z buněk tabulky pomocí indexů pole rovných číslům řádků a sloupků v původní tabulce. Když jsou hodnoty v oblasti takto uloženy do proměnné typu Variant, indexy vzniklého pole jsou vždy číslovány od jedné, nikoli od nuly, bez ohledu na příkaz Option Base v deklarační části modulu. Vzniklé pole má také vždy dva rozměry, i když by oblast měla jen jeden řádek nebo sloupek.
Příkaz Data = Selection je jiný než příkaz Set Data = Selection, který by do proměnné Data uložil oblast s daty tabulky jako objekt.
Na začátku jsou v makru deklarovány 2 proměnné typu pole PromazanáData a TransponovanáData bez udání rozměrů, protože není předem známo, jak velká tabulka bude makrem zpracovávána. Vzhledem k tomu, že se do nich bude přenášet obsah buněk, musí být datovým typem v těchto polích Variant.
Příkazem ReDim se upraví velikost polí podle velikosti tabulky. Přitom se využívá pro zjištění počtu řádků a sloupků tabulky funkce UBound.
Ve For cyklu se do pole PromazanáData uloží data z těch rádků tabulky, které nemají být vymazány, a zjistí se počet takových řádků.
V poli PromazanáData jsou po této operaci na prvních řádcích řádky, které mají v tabulce zůstat, a na ostatních jsou prázdné hodnoty. Toto pole se proto může vložit na původní místo datové části tabulky.
Kdybychom potřebovali pole PromazanáData původně dimenzované na celou tabulku zkrátit na počet zachovaných řádků, budeme potřebovat řádky kódu, které jsou zakomentovány. Při této operaci je nutné pole PromazanáData transponovat, protože funkce ReDim může měnit pouze počet sloupků (poslední rozměr) pole, pokud je volána s klíčovým slovem Preserve, se kterým musí být volána, aby byla v poli zachována data. Potom se změní počet řádků původního pole PromazanáData a to bez klíčového slova Preserve, aby bylo možné změnit i počet řádků (nejen počet sloupků), a tím se vynulují data. Data se do pole PromazanáData zkopírují jako výsledek transponování zkráceného pole.
Sub PromazáníTabulkyVPoli()
Const Vymazat As String = "Vymazat"
Const PořadíSloupkuVymazat As Integer = 4
Dim AdresaPrvníBuňky As String
'Dim PočetDatovýchŘádků As Integer
'Dim PočetVymazanýchŘádků As Integer
Dim Data As Variant
Dim PromazanáData() As Variant
'Dim TransponovanáData() As Variant
Dim i As Integer, j As Integer, k As Integer
Selection.CurrentRegion.Select
AdresaPrvníBuňky = Selection.Cells(1).Address
Selection.Offset(1, 0).Select
Selection.Resize(Selection.Rows.Count - 1).Select
'PočetDatovýchŘádků = Selection.Rows.Count
Data = Selection
ReDim PromazanáData(1 To UBound(Data, 1), 1 To UBound(Data, 2))
'ReDim TransponovanáData(1 To UBound(Data, 2), 1 To UBound(Data, 1))
k = 0
For i = 1 To UBound(Data, 1)
If Data(i, PořadíSloupkuVymazat) <> Vymazat Then
k = k + 1
For j = 1 To UBound(Data, 2)
PromazanáData(k, j) = Data(i, j)
Next j
End If
Next i
'PočetVymazanýchŘádků = PočetDatovýchŘádků - k
'If PočetVymazanýchŘádků > 0 And PočetVymazanýchŘádků < PočetDatovýchŘádků Then
' TransponovanáData = WorksheetFunction.Transpose(PromazanáData)
' ReDim Preserve TransponovanáData(1 To UBound(Data, 2), 1 To k)
' ReDim PromazanáData(1 To k, 1 To UBound(Data, 2))
' PromazanáData = WorksheetFunction.Transpose(TransponovanáData)
'End If
Selection.ClearContents
'Range(AdresaPrvníBuňky).Offset(1, 0).Select
'Selection.Resize(UBound(PromazanáData, 1), UBound(PromazanáData, 2)).Select
Selection = PromazanáData
End Sub
Zrychlení vykonávání maker
Metoda Select a Activate
Je-li makro řešeno tak, že nevybírá a neaktivuje objekty, je rychlejší.
ScreenUpdating
Nastavíme-li vlastnost ScreenUpdating objektu Application na hodnotu False, vypne se obnovování obrazovky, což podstatně zrychlí vykonávání makra obzvlášť, když makro mění objekty na obrazovce.
V případě, že se v průběhu makra objeví uživatelský formulář, je vhodné před zobrazením formuláře obnovování obrazovky zapnout příkazem Application.ScreenUpdating = True, aby při případném pohybu formuláře po obrazovce aplikace nedošlo k vymazávání prostoru pod formulářem.
DisplayAlerts
Makro může vykonat akci, která se implicitně musí odsouhlasit uživatelem. Takovou operací je například odstranění listu.
U maker obvykle není žádoucí, aby za jejich běhu musel uživatel odklikávat dotazy a varování aplikace, především z toho důvodu, že kliknutí, která by například zrušila operaci, by mohla vést k chybě makra, protože s ní makro nepočítalo.
Zobrazování message boxů s dotazy a varováními aplikace se dá vypnout nastavením vlastnosti DisplayAlerts objektu Application na hodnotu False, viz následujcí příklad.
Sub VymažList()
ThisWorkbook.Worksheets.Add , Worksheets(Worksheets.Count), 10 'Přidání 10 listů za poslední list
Application.DisplayAlerts = False
Worksheets(Worksheets.Count).Delete 'Odstranění posledního listu
Application.DisplayAlerts = True
End Sub
Calculation
Některé funkce Excelu jsou volatilní. To znamená, že se přepočítávají, i když se jejich vstupní buňky nemění. Pokud to má vliv na rychlost makra, můžeme na jeho začátku vypnout přepočítávání příkazem Application.Calculation = xlCalculationManual a na konci makra zapnout přepočítávání příkazem Application.Calculation = xlCalculationAutomatic, viz příklad.
Evaluate
Metoda Evaluate objektu Application může zefektivnit zápis a běh kódu.
Dokumentace
Diskuze
Metoda ExecuteExcel4Macro objektu Application umožnuje získat hodnotu v buňce neotevřeného sešitu. (Ušetří se čas na otevírání sešitu.)
V následujícím příkazu se do proměnné a uloží hodnota buňky A1 listu s názvem List1, aniž by sešit Moje data.xls musel být otevřen.
a = ExecuteExcel4Macro("'C:\Data\[Moje data.xls]List1'!R1C1")
Omezení:
- Na buňky se lze odkazovat pouze ve stylu R1C1
- Na listy se lze odkazovat pouze pomocí jejich vlastnosti Name, nikoli například Worksheets(1), takže jejich jména musí být předem známa.
Toto řešení je založeno na příkladu ze stránek Johna Walkenbacha.
Následující makro uloží na aktivní list aktivního sešitu buňky z prvních 50 řádků a prvních 50 sloupků na listu s názvem List1 neotevřeného sešitu Moje data.xls.
Sub NapišHodnoty()
Dim i As Integer, j As Integer
Dim Počátek As Single, Konec As Single
Počátek = Timer
For i = 1 To 50
For j = 1 To 50
Cells(i, j) = ExecuteExcel4Macro("'C:\Data\[Moje data.xls]List1'!R" & i & "C" & j)
If Cells(i, j) = 0 Then Cells(i, j) = ""
'Prázdné buňky (ty co nemají data) vrátí metoda ExecuteExcel4Macro jako nulu.
'Takto tomu lze zabránit, ale potom budou datové buňky s hodnotou nula prázdné.
'Buňky se vzorcem vrátí metoda ExecuteExcel4Macro jako výslednou hodnotu.
Next j
Next i
Konec = Timer
MsgBox Konec - Počátek, , "Trvání v sekundách"
End Sub
Rychlost tohoto makra není příliš veliká. Bude patrně užitečné v případě, kdy je potřeba z velkého množství excelovských sešitů zjistit jen malé množství dat.
Pokud jsou známy názvy oblastí v zavřeném sešitu, nabízí se řešení v podobě příkazu
a = ExecuteExcel4Macro("'C:\Data\Moje data.xls'!MojeOblast")
Toto řešení vrací jen jedinou hodnotu z jediné buňky, i když je v oblasti s názvem MojeOblast více buněk, takže není dobré.
Je však možné získat všechny hodnoty z pojmenované oblasti jako výsledek maticového vzorce
='C:\Data\Moje data.xls'!MojeOblast
zadaného do oblasti tak velké, jak je velká oblast MojeOblast. Podobného výsledku dosáhneme, když zkopírujeme oblast pomocí Vložit jinak - Vložit propojení.
Z toho můžeme odvodit, že makro NapišHodnoty nemusí využívat metodu ExecuteExcel4Macro a místo ní vloží do buňky propojení v podobě vzorce, který se zapíše do buňky při kopírování oblasti pomocí Vložit jinak - Vložit propojení, viz následující příklad
Sub NapišHodnotyLink()
Dim i As Integer, j As Integer
Dim Počátek As Single, Konec As Single
Počátek = Timer
For i = 1 To 50
For j = 1 To 50
Cells(i, j).FormulaR1C1 = "='C:\Data\[Moje data.xls]List1'!RC"
If Cells(i, j) = 0 Then Cells(i, j) = ""
Cells(i, j).FormulaR1C1 = Cells(i, j).Value 'Zruší se propojení.
Next j
Next i
Konec = Timer
MsgBox Konec - Počátek, , "Trvání v sekundách"
End Sub
Toto makro je ale o něco pomalejší.
Efektivnější způsob importu celých tabulek je pomocí nabídky Data - Importovat externí data.