Visual Basic for Applications,
VBScript
(Visual Basic – Scripting Edition)
David Zbíral
Ediční poznámka
Tento materiál není vyváženou učebnicí jazyků či „dialektů“ Visual Basic for Applications a VBScriptu. Mnoho věcí vynechává, obsahuje velmi nestejně propracované části a asi taky nějaké chyby, včetně chyb v terminologii, a taky různá svědectví o tom, co jsem uvést do chodu nedokázal. Pro podrobnější seznámení je dobré nahlédnout do specializovaných knih, například těch, které se uvádějí níže v Použitých zdrojích.
Pokud nějaké chyby jakéhokoli rázu najdete, dejte mi prosím vědět.
Materiál není rozdělen na části o různých edicích VB (VBA, VBS), protože jejich jádro je společné. U některých postupů se výslovně uvádí, které edice se týkají. Když něco, o čem píši, že to jde, nefunguje, tak se to dost možná týká jiné edice VB.
Někde uvádím jako syntaxi něco, co ve skutečnosti není vypsáno ve své nejobecnější podobě, např. řeknu, že syntaxe je fso.MoveFolder zdroj, cíl
, místo abych vypisoval syntaxi objekt.MoveFolder zdroj, cíl
s poznámkou, že se za objekt dosazuje vždy identifikátor objektu FileSystemObject.
Licence
Tento materiál ani jeho části není dovoleno převzít a publikovat jinde (např. na jiných stránkách, na CD doprovázejících časopisy o počítačích apod.) bez předchozího výslovného svolení autora. Vztahují se na něj omezení uvedená v příslušné kapitole stránky O těchto stránkách a všechna jiná, která vyplývají z mezinárodního práva a zákonů jednotlivých zemí. Lze si pořídit jeho kopii (uložit si jej), pro vlastní potřebu vytisknout atd., ale ne jej jakkoli distribuovat či publikovat. Totéž se týká i kódů maker a skriptů.
Základní a obecné informace
- Visual Basic je programovací jazyk vytvořený společností Microsoft. Pracuje v operačním prostředí Windows. Jeho edice, které nás tady budou zajímat: aplikační vydání Visual Basic for Applications (dále VBA) a skriptovací edice Visual Basic Scripting Edition (dále VBScript či VBS).
- VBScript je skriptovací jazyk. Do jazyka jedniček a nul se kompiluje až při běhu. Jiné jazyky se kompilují už po vytvoření, což pak také (zčásti) chrání duchovní vlastnictví; to ale není případ VBS. Pro IE 5 byla vyvinuta technologie, která umožňuje kód skriptu utajit.[1] Utají to hlavně před obyčejnými „vypůjčovateli“, před pokročilejšími ne (jsou schopní to rozšifrovat). Viz Script Encoder na stránkách http://www.microsoft.com.
- Možnosti jazyků Visual Basic for Applications a VBScript: s jejich pomocí můžete docílit efektivní práce se systémem Windows (kopírování souborů, automatické zálohování, vymazávání, instalace), automatizovaně spravovat web (upload, příprava stránek k publikaci, čištění špinavého wordovského HTML), spravovat databáze, ulehčit si hodiny práce při správě sítě, skriptovat na straně serveru i na straně klienta (u skriptování na straně klienta jsou ale možnosti omezené tím, že Mozilla neumí VBScript, takže je lepší naučit se JavaScript), pomocí maker si mnohonásobně rozšířit možnosti Wordu či Excelu atd.
- Nápověda: nápovědu k VBA spustíte nejjednodušeji z editoru VB (který se zase spouští nejlépe pomocí Alt+F11 z aplikací Office). Nápověda k VBS je součástí Microsoft Script Editoru; zkuste zapátrat například po adresáři C:\Program Files\Microsoft Visual Studio\Common\IDE\IDE98\MSE\1029. Z Wordu se MSE spouští kombinací Shift+Alt+F11.
- Všechny zde popsané či naznačené postupy provádíte na vlastní nebezpečí. Za správnost údajů se neručí a za následky se nepřebírá žádná zodpovědnost.
Doprovodná makra a skripty ke stažení
Desítky mých maker jsou ke stažení zde. Ledacos se z nich pochopí a tvoří doprovodný materiál k tomuto dokumentu; na makra se v dalším textu příležitostně odkazuje. Kromě toho jsou mnohá z nich široce využitelná, takže vám mohou ušetřit práci.
Skripty ve VBS (zčásti moje, zčásti převzaté z jedné přílohy časopisu PCWorld a mnou upravené) najdete tady. Vedle své praktické funkce mohou rovněž posloužit jako výukové ukázky. Podrobné komentáře jsou přímo v kódu těchto skriptů, stručné anotace jsou na základní stránce Počítač.
Editory
Obecná poznámka
- Kód lze psát bez obtíží i v Poznámkovém bloku. Ale editory, které umějí vykreslovat syntaxi barevně a případně i opravovat syntaktické chyby, šetří oči i čas. Asi nejvhodnější je Editor jazyka Visual Basic od Microsoftu. Pokud si ale radši syntaxi opravujete sami, může se hodit CodePad, kvalitní editor nejrůznějších kódů, který umožňuje barevné zobrazení syntaxe mnoha jazyků, a přitom se do psaní kódu neplete. Výhodou je, že umí vykreslovat barevně kdeco, takže se dá pracovat u většiny jazyků s ním, tudíž si člověk neplete klávesové zkratky různých editorů (CodePad lze i syntaxe doučovat či učit zcela od začátku – tj. měnit či tvořit definiční soubory syntaxí). Navíc jde o editor uživatelsky komfortní (podporuje např. Undo a Redo).
Editor jazyka Visual Basic
- Spuštění z aplikací MS Office: Alt+F11.
- Změna velikosti písma ve zobrazení kódu: Tools / Options.
- Některou syntax, která ve WSH normálně běží, opravuje editor VB jako chybnou (byť se to stává jen u výjimečných případů). Mimo jiné i proto se na VBS může hodit CodePad, který žádnou kontrolu syntaxe neprovádí, ale umí ji vykreslovat barevně a je docela uživatelsky komfortní (undo a redo, ukládání všech otevřených dokumentů zaráz atd.) a umí syntaxi velkého množství programovacích jazyků.
Konvence zápisu, komentáře
- Odsazování: obvykle se odsazuje o 4 mezery. Odsadit je třeba vždy, když je řádek nebo série řádků podřízena řádkům nad nimi a pod nimi (ne kvůli interpretaci počítačem – ta na tom nezávisí – ale kvůli přehlednosti kódu).
- Velikost písmen: ve VB není pro běh kódu důležitá; ignoruje se (nemluvím samozřejmě o velikosti písmen v hodnotách proměnných: ta se neignoruje). Pro přehlednost je dobré, aby ve výrazech obsahujících více slov přirozeného jazyka, popřípadě jejich částí či zkratek, začínalo každé takové slovo či část velkým písmenem, s možnou výjimkou prvního (takže vbYesNo spíš než vbyesno). Počítači je to jedno, ale kód se lépe čte. Pokud píšete v MS editoru VB, tak velikost písmen v některých klíčových slovech automaticky opravuje.
- Komentáře: je dobré komentáře neopomíjet. Kódu musí rozumět nejen počítač, ale také lidé, v neposlední řadě my sami začas, až budeme chtít provést nějaké změny apod.
- Značí se apostrofem. Lze zapisovat i na konci vykonavatelného řádku. Další, starší zápis je Rem na začátku řádku. Blokový komentář VB bohužel nemá.
- Prázdné řádky: pro přehlednost je také možné vkládat prázdné řádky, případně označené znakem komentáře.
- Zapsání více příkazů na jediný řádek: dělí se dvojtečkami, např.
For Each n in Kolekce: MsgBox n: Next
. Přehlednost to poněkud snižuje, ale někdy se to hodí. - Dělení na více řádků: můžeme psát klidně na dlouhý řádek (i když určitá délka – kolem 1020 znaků – se přesáhnout nesmí), ale špatně se to čte. Proto ve VB dělíme mezerou a znakem podtržítka. (JScript narozdíl od VB pozná konec podle středníku, takže mu je jedno, jestli je to na jednom řádku.)
- Jak rozdělit řádek zprávy v MsgBox: na jednom řádku ukončíme uvozovky, pak mezera a podtržítko, druhý řádek začneme znakem &, mezerou a uvozovkami.
- Při dělení na více řádků je potřeba dávat pozor. Spolehlivě vyzkoušeno, že editor VB neopravoval dělení segmentu, který naplňoval pole jednotlivými prvky, ale první a poslední prvek každého řádku byl ignorován. Poté, co byly spojeny na jediný řádek, tak viděl všechny. Takže ne vždy je dělení bezpečné. Je potřeba si to vyzkoušet.
- Blokové If: blokové If nelze spojovat pomocí dvojteček na jeden řádek; vede to k chybě. Je potřeba použít jednořádkové If.
- Zápis kódu do HTML, např. do stránky zaměřené na výuku VB: je dobré používat párovou značku <code>, která je na kód speciálně určena; používá se málo, a to je škoda, protože nedělá prohlížečům problémy. Značce <code> lze běžným způsobem přiřadit styl přes CSS (včetně barvy atd., pokud nechcete nechat výchozí černou). Mezi <code> a </code> může být zalomení řádku <br>, ale nikoli konec odstavce </p>; to způsobí problémy.
- Jak na to, pokud píšete stránku ve Wordu: já mám soukromou značku <c > a </c > (bez mezery; ta je zde jenom aby se to právě nepřevedlo publikačním makrem na <code> a </code>), jíž v dokumentu normálně uzavírám segmenty kódu (které nesmějí obsahovat tvrdá zalomení řádků, jen měkká); není to v dokumentu nijak zvlášť rušivé. Pak tyto soukromé značky makrem, které mi připravuje stránky k publikaci, v kódu HTML automaticky nahradím za <code> a </code>. Je to asi nejlepší způsob, jak do Wordu kód psát. Používat speciální styl, to by mohlo vést k problémům a je to méně korektní než užívat takovouto speciální značku, a používat místní formátování (označit a zvolit font Courier apod.) znamená hodit čistotu kódu HTML za hlavu. Ještě jednou upozorňuji: pokud užíváte soukromou značku <c > (či nějakou jinou) určenou pro pozdější nahrazení za <code>, tak vkládejte v jejím rámci jen měkká zalomení řádků, žádný konec odstavce.
- Zápis kódu do wordovského dokumentu:
- Rovné dvojité uvozovky ve Wordu: při zápisu kódu do Wordu je někdy problém, protože obvykle bývá nastaveno, aby se rovné uvozovky nahrazovaly českými. Také přiřazení klávesové zkratky pod Vložit / Symbol nepomůže – rovněž dojde k zaměnění za oblé české uvozovky. Ale existuje snadné řešení: vytvořit si na napsání makro a pod Nástroje / Vlastní, karta Příkazy, skupina Makra mu přiřadit klávesovou zkratku, např. Shift+Ctrl+ů. Makro bude v šabloně Normal a bude vypadat třeba takto:
Sub enuv()
Selection.TypeText Chr(34)
End Sub - Odsazení: v dokumentu Word je potřeba v zápisu kódu určeném pro převod do HTML dělat pevnými mezerami, ne běžnými. Jinak po převodu do HTML mizí. Pozor také na to, aby nikde v makrech připravujících stránky k publikaci nebylo zařazeno nahrazení dvou mezer za jednu apod., protože mezera dodaná do Find zasáhne i pevné mezery, tudíž se všechny pevné mezery nahradí za měkké a po převodu do HTML zmizí.
Skriptovací stroj
- Zjištění užitého skriptovacího stroje, a tím i skriptovacího jazyka: ve VBS funkcí ScriptEngine, jejíž možné návratové hodnoty jsou VBScript, JScript a VBA. Příklad:
MsgBox ScriptEngine
. Mimochodem, v makru ve VBA to takhle nejde; jak to jde – pokud vůbec nějak – to nevím. - Verze stroje: ve VBS se zjistí pomocí metody Version objektu Wscript:
Wscript.Version
. - Umístění složky obsahující wscript.exe či cscript.exe:
Wscript.Path
.
Spouštění skriptů a maker
Spouštění skriptu ve Windows
- Běžné spouštění přes Windows Script Host: například ze správce souborů, odentrováním či odkliknutím. Nejobvyklejší možnost.
- Spouštění z příkazového řádku: pomocí příkazu cscript:
cscript c:\skripty\skript.vbs
. Tento způsob spouštění posílá Wscript.Echo do příkazového řádku, což někdy může být výhodné (ale MsgBox je stejná jako normálně). - Plánovač úloh a skripty: skripty lze spouštět přes Plánovač úloh. Ale zjistil jsem, že ne vždy je na samotný Plánovač úloh spoleh.
- .wsh: soubory s touto příponou obsahují informaci, kdy skript spustit. Nic víc o tom ale nevím.
- Jak získat ve VBS cestu k souboru vykonávaného skriptu a jeho název: vlastnost ScriptFullName či ScriptName objektu Wscript. ScriptFullName vrátí úplnou cestu k souboru, ScriptName název souboru včetně přípony.
- Jak zjistit umístění skriptovacího stroje: vlastnost FullName objektu Wscript. Lze toho využít například k větvení postupu pro spuštění přes cscript.exe a wscript.exe.
- Spouštění skriptů z jiných skriptů: je bez problémů možné pomocí metody Run objektu Wscript.Shell. Příklad:
Set wshshell = Wscript.CreateObject(""Wscript.Shell"")
wshshell.Run("C:\skript.vbs")
Skript si lze dokonce z jiného skriptu dynamicky vytvořit (viz kapitolu Textový soubor, kde se uvádí, jak tvořit textové soubory) a pak ho pomocí Run spustit; to se někdy může velmi hodit. - WSF a kombinování skriptů v různých jazycích: soubory skriptů Windows s příponou WSF se řídí syntaxí XML a umožňují mimo jiné kombinovat skripty v JScriptu a VBScriptu. Prvek nejvyššího řádu je <package>, jednotlivé úkoly jsou <job>. Připojuje se instrukce ke zpracování chyb (hodnoty 1 nebo 0, popřípadě true nebo false) a údaj, zda se má pracovat v režimu Debug, či nikoli. Syntaxe:
<?xml version="1.0"?>
<?job error="1|0" debug="1|0"?>
<package>
<job id="j1">
<script language="JScript">
<![CDATA[
/* sem přijde kód skriptu */
]]>
</script>
</job>
</package>
Instrukce CDATA vymezuje blok, který analyzátor XML nemá zpracovávat. Je vhodné to zadávat, aby analyzátor XML nepovažoval žádný znak tohoto bloku za součást kódu XML. - Přidání VBS do vlastních aplikací pro Windows: pomocí zdarma dostupného ovládacího prvku Microsoft Script Control mohou vývojáři Win rozšiřovat své aplikace přidáním podpory pro VBS, JScript aj. Dobré zahrnutí VBS a JScriptu otvírá uživatelům vašeho programu cenné možnosti, takže nelze než doporučit, i když je to práce navíc.
- Jak přerušit běžící skript: vyvoláním okna Správce úloh (kombinací Ctrl+Alt+Del) a ukončením skriptu.
Spouštění a běh makra (VBA)
Různé
- Jak vyvolat dialog Makra: Alt+F8.
- Jak přerušit běžící makro: kombinací Ctrl+Pause.
Události ve Wordu
- Jak do dokumentu vložit makro, které se bude spouštět při otevření: to je snadné. Stačí v editoru VB v podokně Project Explorer kliknout na ThisDocument a napsat do pravého podokna:
Private Sub document_Open()
Call MojeFunkce
End Sub
Kam kód napsat a jak ho upravovat?
- Setkal jsem se s mnoha knihami, které uvádějí užitečné postupy, ale úplnému začátečníkovi není vůbec jasné, jak je použít – neví, kam kód napsat. Tomu se chci vyhnout zařazením této krátké kapitoly, která se to pokusí říci co nejjednodušeji.
- VBScript: kód VBScriptu zapisujte do běžných textových souborů s příponou VBS. Můžete je editovat i například v Poznámkovém bloku.
- Jak skripty upravovat: otevřít je v některém editoru. V některých správcích souborů lze použít k otevření v Poznámkovém bloku klávesu F4 (Servant Salamander aj.), v Průzkumníkovi přichází ke slovu kontextová nabídka pod pravým tlačítkem myši, z níž se vybere Upravit. V Poznámkovém bloku, kde lze podle libosti upravovat. Dokonce lze skript i spouštět a mít ho přitom otevřený v editoru a dolaďovat ho před každým spuštěním; při spuštění se použije poslední uložená verze.
- VBA: Visual Basic for Applications umožňuje tvořit procedury a funkce, které se spouštějí z produktů sady Office. Ve Wordu, Excelu apod. stiskněte Alt+F11 a otevře se vám modul, do kterého můžete makra vpisovat. Spustíte je pod Alt+F8.
Terminologie
- Visual Basic, Visual Basic for Applications, VBScript: někteří programátoři uvádějí, že VBA a VBS nejsou podmnožinami VB. Jinde se naopak uvádí, že VBA je „aplikační vydání Visual Basicu“ a že VBA a VBS nejsou samostatnými jazyky[2] (tj. že spadají pod VB). Ač se nemohu k této otázce vyjádřit úplně kvalifikovaně, myslím, že by se jejich vztah dal vyjádřit následovně: Visual Basic for Applications a VBScript jsou zvláštními skriptovacími odnožemi Visual Basicu. Od základních edic Visual Basicu se liší tím, že potřebují ke svému fungování skriptovací stroj. Ve Visual Basicu se tvoří soběstačnější spustitelné programy (třeba celé rozsáhlé a složité aplikace). Tady se však zkratkou VB obvykle rozumí, poněkud nepřesně, právě VBA + VBS. Proto raději výslovně upozorňuji, abych někoho neuvedl v omyl, že celý tento materiál se týká nikoli Visual Basicu určeného na tvorbu aplikací EXE, nýbrž pouze Visual Basic for Applications a VBScriptu. Něco se dá využít i ve VB, protože to patří ke společnému základu, ale jak si vytvořit vlastní spustitelné programy EXE ve VB, to se zde nedovíte.
- Anglická a česká terminologie: object = objekt, variable = proměnná, constant = konstanta, expression = výraz, property = vlastnost[3], method = metoda, event = událost, specification = (snad) specifikace, return value = návratová hodnota, keyword = klíčové slovo; statement se myslím někdy taky překládá klíčové slovo, nebo taky příkaz (příkaz je asi u něčeho přesnější, například AppActivate je jednoznačně vhodné označit česky za příkaz, a naopak u něčeho je lepší užít obecného sousloví „klíčové slovo“, např. u Dim či Private). Pokud víte víc nebo tu mám nějakou chybu, napište.
- Argument a parametr: někteří autoři odlišují skutečné parametry předávané do procedury od formálních argumentů uvedených v definici procedury. Jiní to nerozlišují.
- Argument: konstanta, proměnná nebo výraz dodávaný do procedury.
- Proměnná: rezervovaná sekce paměti počítače, přesněji stroje VB, kde skript udržuje informaci nebo množinu informací. Měli bychom ji deklarovat neboli dimenzovat. VB standardně povoluje nedeklarované proměnné.
- Prvnímu umístění do paměti se říká inicializace proměnné. Někdy se inicializuje výchozí hodnotou, jindy hodnotu dodá uživatel nebo se načte nějaká dříve uložená hodnota (z databáze, textového souboru apod.).
- Operátor: užívá se ke změně nebo testování hodnoty. Patří sem +, -, *, /, =, &. Členění na aritmetické, srovnávací, zřetězovací a logické: viz v nápovědě VBA pod „Operator“. Rovnítko se používá pro porovnávání nebo přiřazení. Blíže pod zvláštní kapitolou Operátory.
- API: Application Programming Interface (programové rozhraní aplikace). Používá se k vytvoření procedury či funkce, která bude převzata z jiné než standardní knihovny (DLL).
- Seznam zkratek: viz na konci této stránky.
Objekty, metody a vlastnosti
Obecné informace
- Jsou to nástroje, o kterých tvůrci WSH předpokládali, že budou potřeba, tak je do jazyka zabudovali.
- Odkaz na objekt: jsou dva druhy odkazů: ty, které již jsou součástí WHS, a ty, které si vytváříme. Abychom jej mohli vytvořit, potřebujeme proměnnou, která si bude tento odkaz pamatovat.
- Jak získat odkaz na objekt: když chceme získat odkaz na objekt, použijeme příkaz Set.
- Vlastnosti: mají syntaxi Objekt.Vlastnost.
- Metody: mají syntaxi Objekt.Metoda SeznamParametrů.
- Je potřeba si nepoplést, co je objekt a co metoda či vlastnost. Např. nesmyslné
Set jenNazev = fso.GetBaseName(cesta & soubor)
vede ke špatnému fungování skriptu, kdežto když se dá jenjenNazev = fso.GetBaseName(cesta & soubor)
, tak vše funguje bez problémů. - CreateObject: vytvoří objekt. Například:
Set fso = CreateObject("Scripting.FileSystemObject"
. - GetObject: získá odkaz na objekt. Příklad:
Set wordapp = GetObject ( , "Word.Application" )
. Pokud žádná instance neběží, vede GetObject k chybě (takže nejdříve je nutné použítSet objekt = CreateObject(cosikdesi)
). - Vyprázdnění objektu: buď objekt uvolníme explicitně pomocí
Set objekt = Nothing
, nebo se uvolní skončením procedury či skriptu. Lepší je vyprazdňovat objekty explicitně, zvlášť před vyladěním, kdy vykonávání kódu často nedospěje až ke konci skriptu či procedury; jinak jsem se nejednou setkal s obtížemi, například se soubor nedal před restartem počítače smazat, protože se s ním jakoby nadále pracovalo. - FileSystemObject (FSO): jeden z nejdůležitějších objektů, vrchol hierarchie objektů při práci se soubory, adresáři a disky. Obsahuje kolekce Drives, Files, Folders. Každý Folder má kolekci Files obsahující objekty File. Viz pod kapitolou věnovanou souborům.
- Dictionary: objekt, který vybavuje WSH užitečným druhem paměti; umožňuje vytvářet tzv. asociativní pole, kde je položka vymezena ne číslem, ale názvem. Příklad jeho tvorby:
Set d = CreateObject("Scripting.Dictionary")
d.Add "a", "arak"
d.Add "b", "bordeau"
d.Add "c", "calvados"
Objekt Wscript: vlastnosti a metody
- Soubor Wscript odkazuje na běžící skript. Lze ho využít ke získávání různých informací o skriptovacím stroji či samotném běžícím skriptu.
- Vlastnosti objektu Wscript:
- Application: vrátí odkaz na objekt Wscript.
- Arguments: vrátí kolekci argumentů.
Set args = Wscript.Arguments
. - FullName: vrátí úplnou cestu k programu vykonávajícím skript.
- ScriptFullName: vrátí úplnou cestu k běžícímu skriptu.
- ScriptName: vrátí název běžícího skriptu včetně přípony.
- TimeOut: určuje maximální dobu vykonávání skriptu. Jen ve WSH 2.0.
- Metody: CreateObject(identifikátor). Lze též bez Wscript – i tak tahle metoda funguje.
Objekt Wscript.Shell: spouštění programů, otvírání souborů aj.
- Obecné informace: objekt Wscript.Shell umožňuje přístup k jádru Windows, registrům a stavovým proměným. Lze jej využít ke spouštění programů, vytváření zástupců, zobrazování zpráv v dialogových oknech, přístupu k systémovým složkám atd.
- Nejdřív potřebujeme odkaz na objekt Wscript.Shell:
Set wshshell = CreateObject("WScript.Shell")
. - Metoda Run: slouží ke spouštění programů a otvírání souborů. Syntaxe:
wshshell.Run příkaz[, stav okna[, čekat na odezvu]]
. - Příkaz: příkaz je cesta k programu či souboru, doplněná o případné parametry (tytéž, jaké lze zadat do okénka Spustit). U souboru může předcházet instrukce, v jakém programu se má soubor otevřít (viz níže – jde o analogii „Otevřít v programu“).
- Stav okna: 0 skryté, 1 normální, 2 minimalizované, 3 maximalizované, 4 viditelné a v nynějším stavu, ale neaktivní, 5 v nynějším stavu a aktivní, 6 minimalizované, zobrazí se okno, které je „těsně pod ním“, 7 minimalizované neaktivní, 8 v nynějším stavu a neaktivní (neznám rozdíl od 4), 9 obnovené.
- Čekat na odezvu: Boolean (True nebo False). Pokud je specifikováno False, skript nečeká na odezvu od spouštěného programu, nýbrž ihned pokračuje. Pokud je zadáno True či parametr není zadán, tak čeká na odezvu aplikace, zejména na případný chybový kód. Run lze použít k získání návratové hodnoty – kódu této chyby:
r = WshShell.Run("notepad " & Wscript.ScriptFullName, 1, True)
. - Pokud zadáváte tyto volitelné parametry, tak pozor na závorky, mohou působit chybu. Spíš tu závorky nepoužívejte.
- Je často dobré zadávat cesty relativně a kde to je vhodné, používat %SystemRoot%:
wshshell.run ("%SystemRoot%\system32\compmgmt.msc")
. - U některých standardních programů Windows stačí zadat jen název stejným způsobem, jako když používáte Start / Spustit, např. calc či calc.exe.
- Spuštění programu: např.
wshshell.Run ("C:\programy\mozilla\mozilla.exe")
. Pokud jsou problémy, zkuste použít krátkou (dosovskou) cestu, bez mezer; mám ověřené, že to někdy pomůže. (Ostatně, doporučuji si disk vůbec organizovat tak, že v cestách ani názvech souborů nejsou mezery a nejlépe ani diakritika.) - Otevření souboru asociovaným programem: úplně stejně jako spuštění programu:
wshshell.Run("c:\soubor.doc")
. - Otevření souboru jiným než asociovaným programem („Otevřít v programu...“): tam je potřeba dát jednak instrukci, v čem soubor otevřít, jednak cestu k samotnému souboru. Příklad:
Set ws = CreateObject("Wscript.Shell")
ws.run ("notepad C:\test.tmp")
Jde to i s jinými programy, než jsou ty, s nimiž Windows počítá, řekněme třeba s CodePadem, jen je nutné zadávat úplnou cestu k programu, např.:ws.run ("C:\programy\CodePad\CodePad.exe C:\test.tmp")
. - Problémy může působit mezera v názvu adresáře; zkuste, zda je nevyřeší, když do kódu vepíšete cestu ve tvaru pro MS DOS. Z úplné cesty vám dosovskou cestu pohodlně zjistí makro DosovskáCestaAdresáře mezi makry.
- Toto „Otevřít v programu“ lze výborně využít například pro zobrazení výstupu skriptu: prostě v adresáři dočasných souborů (nebo i jinde, ale toto je asi nejčistší postup) vytvoříte skriptem textový soubor, do něj postupně výsledky zapíšete a pak soubor přes Poznámkový blok otevřete. Jak na to:
Set fso = CreateObject("Scripting.FileSystemObject")
tempdir = fso.GetSpecialFolder(2)
tempname = fso.GetTempName
tempfile = fso.BuildPath(tempdir, tempname)
Set txt = fso.CreateTextFile(tempfile)
txt.WriteLine "Výstup skriptu."
Set ws = CreateObject("Wscript.Shell")
ws.run ("notepad " & tempfile)
Díky bezproblémovosti Poznámkového bloku lze soubor i smazat, např. prostě pomocífso.DeleteFile(tempfile)
, aby šlo skutečně jen o dočasný výstup, který může uživatel uložit či ze kterého může něco vykopírovat přes schránku, ale který nezůstává v adresáři dočasných souborů. Musíte však do skriptu vložit pauzu, jinak se soubor smaže dřív, než ho Poznámkový blok stačí spustit. (Smazání nefunguje bezproblémově vždy. Když jsem výše uvedený kód spouštěl jako wordovské makro, šlo vše bez obtíží, i bezSet txt = Nothing
. Když přes WSH, tak pokus o mazání, a to jak pomocí Kill, tak fso.DeleteFile, vyvolával chybu Oprávnění byla odepřena, a to i v případě, že byl soubor již v Notepadu zavřený. Ale když dáte smazání až zaSet txt = Nothing
, tak to jde hladce i přes skript.) - Jak otevřít adresář ve správci souborů:
- V Průzkumníku:
ws.run ("explorer.exe /n, C:\PROGRA~1")
. Pozor na cesty s mezerami – dělají problémy. Pokud je v cestě mezera, tak je třeba zadat krátkou, dosovskou cestu bez mezer (jako v tomto případě k C:\Program Files). Jinak dochází k chybě. Doporučuji si striktně organizovat disk tak, že v cestách nejsou mezery. - V Servant Salamanderu: to je taky snadné, stačí metodou Run spustit Servant Salamander a jako parametr mu předat příslušnou cestu:
ws.Run "C:\salamandr\salamand.exe -L C:\PROGRA~1"
. Uvedenou cestu nahraďte tou, ve které máte Servant Salamander nainstalovaný. - V Total Commanderu: to jde taky, velmi podobně.
- Speciální složky: odkaz na ně se získá s pomocí vlastnosti SpecialFolders objektu Wscript.Shell. Takto například získáme cestu k adresáři obsahujícímu nabídku Start:
nabstart = wshshell.SpecialFolders("StartMenu")
. - Další věci (tvorba zástupců atd.) se probírají v jiných kapitolách, kam tematicky zapadají.
Operátory
- Operátory: přiřazovací (=), aritmetické (+, *, /), operátory řetězení (&, +). Dále například: <> není rovno, <= (menší nebo rovno), >= (větší nebo rovno).
- Nerovná se, je různé od: <>. Tento operátor lze samozřejmě použít i na porovnání řetězců, např.
If pripona <> filtr Then soubor = "odpadni-soubor.tmp"
. - Is: vrátí True, pokud porovnávané objekty odkazují na stejné místo v paměti, a jedná se tedy fakticky o stejný objekt. Syntaxe:
jsoutotozne = objekt1 Is objekt2
, popřípadě v podmínce:If objekt1 Is objekt2 Then
atd. - Závorky určují prioritu operátorů, pokud má být jiná, než je výchozí.
- Operátory, porovnávání proměnných: používají se např. operátory <> a =. Příklad:
If pripona <> filtr And filtr <> "" Then soubor = "odpadni-soubor.tmp"
. - Logické operátory: Not, And, Or, Xor, Eqv.
- Xor: vrací True, pokud je právě jeden z výrazů True. Syntaxe:
vysledek = vyraz1 Xor vyraz2
. - Eqv: testuje, zda se oba výrazy vyhodnotí na stejnou hodnotu.
- Priorita operátorů: nejdříve jsou vyhodnocovány aritmetické, pak řetězící (&), pak srovnávací (=, >= atd.) a nakonec logické (And, Or, Eqv, Xor atd.). Srovnávací mají mezi sebou všechny stejnou prioritu, aritmetické jsou vyhodnocovány zleva doprava s tím, že násobení a dělení má přednost před sčítáním a odčítáním (jeden zdroj toto upřesnění opomíjel, ale ověřil jsem, že to tak opravdu je), logické jsou vyhodnocovány zleva doprava. Prioritu operátorů lze ovlivnit závorkami, například:
If (i > 64 And i < 91) Or (i > 96 And i < 123) Then
atd. Blíže viz nápovědu pod „Operator Precedence“.
Zástupné znaky
- ?: v kterémkoli místě vzoru nahrazuje právě jeden znak.
- #: v kterémkoli místě vzoru nahrazuje právě jednu číslici.
- *: v kterémkoli místě vzoru nahrazuje žádný a více znaků.
- []: v kterémkoli místě vzoru nahrazuje právě jeden znak ze seznamu obsaženého v těchto závorkách, takže "a[bcd]e" mohou odpovídat řetězce abe, ace nebo ade.
- [!]: prvky, které nepatří do seznamu.
- Tyto zástupné znaky nelze použít všude. Například je nelze vpisovat do funkce Replace.
- Zástupné znaky Selection.Find: viz níže pod touto funkcí a taky v Tipech pro práci s počítačem v kapitole věnované Wordu.
Proměnné
Různé
- Proměnná: rezervovaná sekce paměti počítače, přesněji stroje VB, kde skript udržuje informaci nebo množinu informací. Měli bychom ji deklarovat neboli dimenzovat, nicméně VB standardně povoluje nedeklarované proměnné. Každá proměnná má svůj název a datový typ.
- Deklarace (dimenzování) proměnných: provádí se obvykle v hlavičce pomocí klíčového slvoa Dim. Ve VB není deklarace povinná tj. můžeme začít užívat kdekoli v kódu novou proměnnou, aniž jsme ji deklarovali. U složitých procedur se ale deklarace vyplatí.
- Deklarace proměnné včetně datového typu: lze deklarovat i datový typ proměnné; je možné použít také vestavěnou konstantu VB; tím docílíme toho, že s proměnnou bude nakládat, jako by měla vlastnosti dané konstanty. Příklady:
Dim Styl As Style: Dim retezec As String: Dim Seznam as New Collection
. - Proměnné lze deklarovat na jednom řádku:
Dim fso, soubor, jednotka, slozka
. - Nová deklarace proměnných: ReDim. Provádí změnu deklarace dynamického pole nebo změnu jeho indexových rozsahů.
- Deklarace proměnných je v editoru VB výhodná mimo jiné proto, že se velikosti písmen v názvech proměnných automaticky přizpůsobují podobě, jaká je v deklaraci, což zrychluje psaní: lze psát samá malá a nechat editor, ať sám velikost upravuje.
- Deklarace proměnných pro celý projekt: aby byla proměnná dostupná všem procedurám projektu, v její deklaraci se užívá klíčové slovo
Public
. - K deklaraci proměnných lze přidávat komentář, k čemu budou sloužit (zejména pokud to není jasné).
- Příkaz Option Explicit si vynutí deklaraci všech proměnných. Nedeklarované proměnné následující za příkazem Option Explicit generují chybu 800A01F4. Option Explicit najde použití zejména u složitých skriptů, kde je lepší mít o proměnných přesný přehled.
- Jak pojmenovávat proměnné:
- Název by měl být výstižný a srozumitelný (a to i jiným osobám). Výstižný název často zabrání pokušení užít proměnnou k uložení dat, které do ní nepatří, a vyhnout se tak nesystémovosti kódu a možným chybám.
- V jakém jazyce má název být? Záleží na tom, jak široký záběr svému skriptu připisujete. Pokud je určen i nečesky mluvícím, měly by být názvy proměnných anglicky. Při užívání angličtiny je samozřejmě potřeba dát si pozor, aby nešlo o nějaké vyhrazené klíčové slovo či konstantu VB.
- Doporučuji nepoužívat diakritiku. VBA to sice zvládá, ale může to působit potíže na počítačích s jinou lokalizací Windows apod. U názvů procedur a funkcí už to není tak jednoznačné, pokud je nečte jen počítač, nýbrž i uživatel (například názvy wordovských maker). Tam já diakritiku ve VBA používám. Ve VBS ne, protože WSH, alespoň v mé verzi, hlásí při použití chybu „Neplatný znak“ a zarazí se. Takže shrnuto: pokud je to makro, s jehož názvem přijde uživatel do styku, a je ve VBA, je to nejednoznačné. Pokud s ním do styku nepřijde, tak je rozhodně lepší diakritiku nepoužívat. Někdy je dokonce nutné se v názvu podprogramů diakritice vyhnout: ve VBS působí chybu.
- Jednotnost názvu proměnných: bývá docela užitečné užívat ve všech kódech pro tentýž údaj či objekt proměnnou stejného názvu, například txt pro textový soubor, fso pro FileSystemObject atd.
- Pokud název proměnné obsahuje víc slov, je dobré, aby každé slovo začínalo velkým písmenem (včetně prvního či kromě něj), například NazevSouboruPrac. Ne že bych to tak vždycky dělal, ale přehlednost to zvyšuje.
- Proměnné by měly mít specifický název, který vypovídá něco o jejich účelu či o datech, která obsahují. Například nazývat kolekci Kolekce, to není správné (ač se to tak pro názornost dělá v některých výukových materiálech, i na některých místech tohoto dokumentu). Lepší je ji nazvat podle toho, jaká data obsahuje: Adresare, Konvertory, Zamestnanci apod.
- Změna názvu proměnných a objektů: při přejmenovávání proměnných a objektů není dobré název měnit ručně; lepší je použít v daném editoru hromadné nahrazení či nahrazení po jednom, jinak se často někde zapomene starý název a skript pak nefunguje správně.
- Statická proměnná: taková proměnná, která si zachová hodnotu, dokud kód běží.[4] Deklaruje se pomocí klíčového slova Static. Příklad:
Static promenna As Long
. Ve VBS působí tato deklarace chybu. - Zásada ekonomického využívání proměnných: pokud už nějaké přiřadíme hodnotu, tak je dobré ji využít všude, kde má být užita hodnota, kterou nese. Např. pokud máme přiřazenou hodnotu
zprava1 = "Předpověď počasí"
, tak pokud chceme zobrazit zprávu „Předpověď počasí: polojasno“, tak použijemepredpoved = zprava1 & ": polojasno"
. Tady to má zrovna málo smyslu, ale u proměnných, které zabírají víc paměti či víc kódu, to smysl dostává. - Něco jiného je ale používání proměnné pro různý obsah. To vede spíš ke zmatku a často to má na svědomí těžko odhalitelné chyby (u složitějších skriptů). Například pokud do proměnné PredpovedPocasi zapíšete „Dobrý den“, tak to není v pořádku.
- Vložení hodnoty do proměnné: nejobvyklejší je vkládání pomocí operátoru =. Příklad:
promenna = 5000
. Nebo:promenna = ""
. - Získání hodnoty od uživatele: snadné přes InputBox:
nazevSouboru = InputBox("Zadejte název souboru včetně přípony:")
. - Vložení označeného textu do proměnné ve Wordu: je to velmi jednoduché:
Retezec = Selection.text
. Když se pak ale někam vepíše, tak se vloží jako prostý text, nezachovává formátování. S formátovaným textem je asi nutné pracovat přes schránku. - Sdílení proměnných různými funkcemi a procedurami: viz kapitolu o volání funkcí.
- Rozsah proměnné:
For i = 33 To 10000: Retezec = Retezec & i & " " & ChrW(i) & vbCrLf: Next i
. - Neopakování zpracování řetězce: když chceme zajistit, aby se s některým řetězcem pracovalo jen v tom případě, že shodný řetězec ještě nebyl zpracován (zejména v cyklu), je dobré neužít prosté naskládání do seznamu a pak porovnávání se seznamem pomocí InStr, nýbrž naskládání s použitím distinktivních, jinde ve zpracovávaném textu se nevyskytujících znaků, které prvky vkládané do seznamu dělí od sebe, aby řetězce nesplývaly. Podmínka pak bude vypadat například takto:
If InStr(JizZpracovano, "[" & AktualniPolozka & "]") Then
atd. a každé proběhnutí cyklu bude do seznamu JizZpracovano přidávat právě zpracovanou položku:JizZpracovano = JizZpracovano & "[" & AktualniPolozka & "]"
Ověřování či zjišťování hodnoty a datového typu proměnné (IsArray, IsEmpty apod.)
- VarType(název proměnné): funkce VarType vrací kód charakteristiky proměnné. Návratové hodnoty: viz tabulku v nápovědě pod VarType Function. Empty: 0. Datum: 7. Řetězec: 8. Objekt: 9. Pole: 8192.
- TypeName(název proměnné): funkce TypeName vrací String určující typ obsahu vstupní proměnné: Byte, Integer, Error atd. Blíže viz nápovědu. Příklad:
MsgBox TypeName(ActiveDocument.Content)
. - IsEmpty(výraz): ověřuje, zda má výraz hodnotu Empty. Empty není totéž jako prázdný řetězec. Empty je neinicializovaná proměnná či proměnná, které se hodnota Empty přiřadí. Že Empty není totéž jako řetězec nulové délky, si lze ověřit například pomocí funkce IsNumeric, kde vstupní hodnotou jednou bude "", podruhé neinicializovaná proměnná: jak jsem zjistil, IsNumeric vrací pro prázdný řetězec False, kdežto pro Empty vrací True. Empty, Null a řetězec nulové délky jsou tři odlišné věci, jak potvrzuje nápověda pod IsNull Function.
- Pozor, IsEmpty vrací správnou hodnotu jen pokud je testovaná proměnná Variant (potvrzuje to i nápověda). Takže když do deklarace funkce dáte např.
Optional kolikrat As Integer = Empty
a pak testujete kolikrat přes IsEmpty, nedostanete správný výsledek; IsEmpty takto vrací vždy False. - IsNull(výraz): vrací True, pokud je hodnota výrazu Null. Jinak vrací False. Pokud je testován výraz sestávající z více než jedné proměnné, vrací True, pokud má kterákoli z proměnných hodnotu Null. Null je potřeba testovat přes funkci IsNull, ne přes porovnávací operátor (např.
If promenna = Null
čiIf promenna <> Null
), poněvadž tyto podmínky nejsou nikdy pravdivé. To je způsobeno skutečností – jak vysvětluje nápověda pod „IsNull Function“ – že výraz obsahující Null je sám Null, tudíž i False. - Co to vlastně znamená, když je něco Null: hodnota Null indikuje, že proměnná neobsahuje žádná platná data (jak poznamenává nápověda, např. pod VarType Function). Hodnota Null je buď výsledkem přímého přiřazení této hodnoty nějaké proměnné, nebo výsledkem operací mezi výrazy, které jsou Null.
- IsNumeric(výraz): ověřuje, zda je výraz číselný. Pokud ne, vrací False. Pokud je smíšený (např. "1a"), vrací False. Pokud je proměnná vbNullString (tj. ""), vrací False. Pokud je proměnná Empty (například nebyla inicializována), tak vrací True, jak si můžete ověřit na kódu
MsgBox IsNumeric(cosikdesi)
. Pokud je proměnná Null, vrací False. Jestliže chceme prověřit všechny prvky pole, tak je potřeba pole buď nejdřív zřetězit či spojit pomocí Join a pak otestovat jako řetězec (to pokud chceme testovat pole jako jeden celek), nebo testovat jednotlivé prvky (to pokud chceme zjišťovat i to, který prvek je či není numerický); když je totiž do IsNumeric jako parametr předáno pole, vrací funkce False i v případě, že pole obsahuje samé číselné hodnoty. (testoval DZ) - Lze ověřit, zda jde o písmena, popř. o alfanumerický řetězec? Ve VB 6 není funkce, která by to uměla. Je možné použít funkci API IsCharAlpha a IsCharAlphaNumeric. Nicméně jsem si také sestavil své vlastní funkce IsAlpha a IsAlphaNumeric, které najdete pod těmito názvy mezi mými makry a které zahrnují například i písmena řecké, hebrejské či arabské abecedy; dají se použít úplně stejně jako IsNumeric, například
MsgBox IsAlpha("abcd§")
čiIf Not IsAlphaNumeric(nazevSouboru) Then
atd., jen musejí být pochopitelně umístěny v každém skriptu, který s nimi pracuje. Pokud jsou umístěny do modulu NewMacros globální šablony Wordu, tak je lze používat ve všech wordovských makrech, které jsou součástí modulu NewMacros. Pokud vás zajímají jen tyto funkce a ne jejich vysvětlení, tak tento odstavec ani nemusíte dočítat. Další komentáře k těmto funkcím jsou v samotném kódu. Jsou založeny na porovnávání řetězce s řetězcem písmenných znaků sestavených pomocí ChrW(i). - Komentář k mým funkcím IsAlpha a IsAlphaNumeric: je buď potřeba zjišťovat, zda je znak obsažen v řetězci znaků, které programátor vypsal jako alfanumerické, nebo se naučit pracovat s API. Mám na to jeden trik: kombinaci IsNumeric a cyklu skládajícího kódy ChrW. Blíže viz funkce IsAlpha a IsAlphaNumeric mezi mými makry. Následuje jednodušší příklad pouze pro ASCII určený k pochopení, jak se s tím pracuje:
JeAlfa = False
For i = 65 To 90
If znak = Chr(i) Then JeAlfa = True
Exit For
Next
A pak další dávka znaků:
JeAlfa = False
For i = 97 To 122
If znak = Chr(i) Then JeAlfa = True
Exit For
Next
Lze tak testovat jednotlivé znaky. Ale výhodnější je nejdřív si sestavit pomocí cyklu For ... Next řetězec písmenných znaků (viz moje funkce IsAlpha a IsAlphaNumeric) a s ním pak porovnat jednotlivé znaky testovaného řetězce pomocí funkce InStr:
For i = 1 To Len(retezec)
atd.
znak = Mid(retezec, i, 1)
If InStr(alfanumZnaky, znak) <> 0 Then
Takže rozhodně není potřeba mechanicky vypisovat řetězec písmenných znaků, protože se otvírá možnost použití cyklu a funkce ChrW. Konkrétně se na to můžete podívat na moje již zmíněné funkce IsAlpha a IsAlphaNumeric, ze kterých se přímo pochopí možná i víc než z tohoto komentáře. - IsDate(výraz): ověřuje, zda jde o datum.
- IsArray(proměnná): True nebo False podle toho, jestli je proměnná polem.
- IsObject(identifikátor): vrací True, pokud identifikátor zastupuje nějaký objekt. Jinak vrací False.
- IsMissing(argument): vrací True, pokud nebyl volitelný parametr procedury či funkce zadán. Jinak vrací False. Ale funguje jen na datový typ Variant, jak jsem zjistil a jak potvrzuje nápověda. Takže pokud deklarujete datový typ argumentu jiný než Variant, nepoužívejte na jeho testování IsMissing, nýbrž mu přiřaďte nějakou výchozí hodnotu a testujte proměnnou na tuto hodnotu, např.
Optional kolikrat = Empty ... If kolikrat = Empty Then
atd. (pozor i na IsEmpty; také funguje jen na Variant). Někdy je vhodné, aby to bylo něco distinktivního, např. řetězec, číslo apod., o kterém si myslíte, že nebude nikdy do podprogramu jako parametr předáno. - Příklad z praxe: že je IsMissing nepoužitelná na Integer a String, si můžete ozkoušet např. na funkci Nahradit mezi mými makry; ta obsahuje podmínku, že pokud je IsMissing True, tak se mají provést všechna nahrazení, pokud ne, tak jen jedno. Zkuste si otevřít nový dokument, vepsat do něj "abc abc abc abc", dodat do deklarace kolikrat ještě "As Integer" a zavolat funkci z makra, např. makra zkouška(), pomocí Call Nahradit("abc", "123"). IsMissing bude False, a provede se tudíž jen jedno nahrazení. Zkuste deklarovat kolikrat As String a také bude IsMissing vždy False.
Konstanty
- Konstanty můžeme rozdělit na vestavěné a nevestavěné. Ty nevestavěné dimenzujeme pomocí klíčového slova Const. Syntaxe:
Const název_konstanty = hodnota
. Příklad:Const pozdrav = "Ahoj"
neboConst pocet = 5000
. Ve VBScriptu mi působí klíčové slovo Const chybu. - Vestavěné konstanty se rozebírají pod kapitolami, kam tematicky patří.
Datové typy
- Určují typ dat, jež proměnná obsahuje.
- Proč deklarovat datový typ proměnných: zrychlí to provádění kódu, zmenší to nároky na paměť, zamezí to možným chybám.
- Jak deklarovat datový typ proměnných:
Dim proměnná As datový typ
. Příklad:Dim i As Integer
. Pokud chcete deklarovat datový typ argumentu předávaného do funkce nebo procedury, tak je nejlepší tak činit v deklaraci funkce:Function MojeFunkce(retezec As String, j As Integer, pole())
. - Jednotlivé typy: viz nápovědu pod Data Type Summary, Using Data Types Efficiently, Type Conversion Functions.
- Výchozí typ je Variant. Takže pokud není datový typ deklarován, pokládá se proměnná za Variant.
- Integer: celá čísla od -32 768 do 32 767.
- Long: celá čísla od -2 147 483 648 do 2 147 483 647.
- String: řetězec.
- Boolean: hodnoty True a False.
- Mezi datovými typy lze převádět. O převádění pojednává kapitola Konverzní funkce.
- Uživatelem definované typy: umožňují označit jedním identifikátorem skupinu položek různých datových typů.
Type Osoba
[5]
Prijmeni As String
Jmeno As String
DatumNarozeni As Date
RodneCislo As Double
NasZamestnanec As Boolean
End Type
Potom můžeme kdekoli deklarovat proměnou Dim xy As Osoba. Na jednotlivé složky typu se odkazuje pomocí tečkové notace:Osoba.Prijmeni = "Zbíral"
.
Řetězce
Různé
- Porovnávání: normálně přes rovnítko.
If retezec = "nazdar" Then
atd. - Řetězec nulové délky: odpovídá mu konstanta vbNullString. Další možnost zápisu je "", ale víc se doporučuje vbNullString; důvod neznám a možná je volba spíš záležitostí estetickou. Příklad:
If cesta = vbNullString Then Exit Function
, popřípaděIf cesta = "" Then Exit Function
. Prázdný řetězec vůbec není totéž jako Empty ani jako Null. - Spojení řetězců: provádí se pomocí operátoru &. Příklad:
retezec = retezec1 & retezec2 & "dodatek"
. - Délka řetězce ve znacích: zjišťuje se funkcí Len se syntaxí
Len(řetězec)
. - Délka řetězce v bajtech: zjišťuje se funkcí LenB se syntaxí
LenB(řetězec)
. - Obrácení řetězce: ve VB 6 funkce StrReverse.
retezec = "abc": retezec = StrReverse(retezec)
. Pokud chcete docílit větší kompatibility (například s Office 97), neužívejte funkci StrReverse, nýbrž načtěte řetězec do řetězce nového odzadu pomocí cyklu Do ... Loop a funkce Mid. - Celý řetězec malým písmem: funkce LCase.
TextMalym = LCase(text)
. Lze zapsat i do stejné proměnné:text = LCase(text)
. - Celý řetězec velkým písmem: funkce UCase.
TextVelkym = UCase(text)
. - StrConv: konverzní funkce. Syntaxe:
StrConv(řetězec, typ konverze)
. - Velká písmena na začátku každého slova řetězce: za typ konverze se dosadí vbProperCase. Příklad:
retezec = "cosi kdesi"
.
retezec = StrConv(retezec, vbProperCase) - Vše velkým: vbUpperCase.
- Vše malým: vbLowerCase.
- Do Unicode: vbUnicode.
- Z Unicode: vbFromUnicode.
- Oříznutí řetězce od okrajových mezer: funkce LTrim(retezec) ořízne řetězec zleva, RTrim zprava, Trim z obou stran.
- Řetězec mezer: vytvoří se prostřednictvím funkce Space. Argument určuje, o kolik mezer má jít. Např.
Space(5)
vrátí 5 mezer. - Nahrazování: k nahrazování je určena velmi důležitá funkce Replace. Má syntaxi Replace(v čem, co, za co[, od kolikátého znaku začít[, počet nahrazení[, srovnávací metoda]]]). Od kolikátého znaku začít: výchozí je první. Počet nahrazení: výchozí je -1, což znamená provést všechna možná nahrazení. Dá se nahrazovat za jakýkoli řetězec: stejně dlouhý, delší, kratší i nulové délky (poslední zmíněný případ je, jinak řečeno, vymazávání). Pozor na to, aby byl, pokud zadáváte počet nahrazení, zadán i argument od kolikátého znaku začít; když jsem dal jen
nazev = Replace(nazev, "www.", "", , 1)
, působilo to ve VBS chybu. Po přidání čísla 1 před čárku běželo vše správně. (DZ)
retezec = "abcabcabc"
retezec = Replace(retezec, "ab", "1")
MsgBox retezec 'Řetězec je nyní roven "1c1c1c". - Porovnávání, zda obsahuje jiný řetězec: funkce InStr. Syntaxe:
InStr([kolikátým znakem začít,] prohledávaný řetězec, hledaný řetězec[, srovnávací metoda])
. - Argumenty funkce InStr, podrobnější komentář: číslo, od kolikátého znaku řetězce má začít s porovnáváním; řetězec, v němž hledáme; řetězec, který hledáme (jímž může být samozřejmě i proměnná, nebo také konstanta VB). Srovnávací metoda: vbBinaryCompare (rozlišuje malá a velká písmena, výchozí) nebo vbTextCompare (ignoruje rozdíl malých a velkých písmen).
- Hledá první výskytod místa, které určíme, nikoli počet výskytů. Vrací pořadové číslo začátku hledaného řetězce v prohledávaném řetězci (nikoli od místa, od kterého prohledáváme). Pokud hledaný řetězec vůbec nebyl nalezen, vrací 0.
- Funkce má široké použití. Viz nápovědu pod „InStr example“ (ale většinu poznatků, a ještě některé navíc, najdete přímo zde).
- Příklad:
jemail = InStr(1, slovo, "@")
atd.
If jemail <> 0 Then - Jiný příklad: obsahuje tabulátor?
If InStr(1, odstavec, vbTab) <> 0 Then MsgBox "Odstavec obsahuje tabulátor."
. - Porovnávání bajtů: funkce InStrB se stejnými argumenty jako InStr.
- Pozor na jednu záludnost, „Not InStr“ a „InStr = 0“ vůbec nejsou ekvivalentní. Je potřeba používat InStr = 0, popřípadě InStr = False, ne však Not InStr. Neekvivalenci si můžete snadno ověřit na této proceduře, kterou lze spustit například jako wordovské makro a která testuje, zda je v řetězci "abc" obsažen znak "a". Varianta s „Not Instr“:
Sub zk()
Znak = "a"
test = "abc"
If Not InStr(test, Znak) Then
MsgBox Chr(34) & Znak & Chr(34) & " není obsaženo v řetězci " & Chr(34) & test & Chr(34) & "."
Else
MsgBox Chr(34) & Znak & Chr(34) & " je obsaženo v řetězci " & Chr(34) & test & Chr(34) & "."
End If
End Sub
Vyhodnocení je chybné: tvrdí se nám, že "a" není obsaženo v "abc". Když si řádekIf Not InStr(test, Znak) Then
nahradíte zaIf InStr(test, Znak) = 0 Then
, dostanete správný výsledek. Testoval jsem pečlivě. Vysvětlení: je to dáno tím, že funkce InStr zde vrací 1 a Not 1 je -2 (jak si lze zkusit kódemjednicka = 1: negacejednicky = Not jednicka: MsgBox negacejednicky
); program tedy vyhodnocuje logicky správně (podmínka vlastně zníIf -2 Then
, takže je vždy pravdivá, jak si lze ověřit na příkladuIf -2 Then MsgBox "Vždy pravdivá podmínka."
). Jenže to u InStr vede ke zcela zmatečnému výsledku, takže je potřeba používat variantu s InStr = 0, nikdy variantu s Not. Z řečeného již jasně vyplývá, že zápisy InStr Not a InStr = 0 nedávají ani přesně opačné výsledky, jak si můžete ověřit: když ve variantě makra s Not dosadíte do Znak písmeno a, b nebo c, tak se vždy objeví zpráva, že není obsaženo, a když dosadíte d, které tam opravdu není, tak taky. Působí to zmíněná vždy pravdivá podmínka, která zamezuje tomu, aby se vůbec někdy vykonal blok pod Else. Vyplývá z toho, že zápis InStr s Not je, přinejmenším v uvedené syntaxi, zcela nepoužitelný. Pokud znáte nějakou syntaxi, kde s Not použít jde a dává správný výsledek, pokud jste dospěli testováním k jinému výsledku či pokud máte jiný názor na vysvětlení, dejte vědět. - Zjišťování obsaženosti prázdného řetězce funkcí InStr: vyzkoušel jsem, že když pomocí InStr testujeme obsaženost prázdného řetězce – což většinou neděláme vědomě, protože je to nesmysl, ale dochází k tomu, když se testuje obsaženost proměnné, která z nějakého důvodu nabyla hodnoty "" – tak funkce vrací 1 (dokonce například i pokud hledáme prázdný řetězec v hodnotě proměnné, jejíž datový typ je Integer). Nulu InStr vrací při hledání prázdného řetězce jen pokud jej hledáme v proměnné, která je sama Empty či prázdný řetězec. To je zajímavé, že v prázdném řetězci není prázdný řetězec obsažen; řekl bych, že to lze vnímat jako logickou chybu, ale ať tak či tak, je potřeba s tím počítat; otestováno pečlivě.
- InStrRev: hledá odzadu (ale vrací vzdálenost od začátku řetězce, ne od konce). Má trochu jinou skladbu než InStr:
InStrRev(prohledávaný řetězec, hledaný řetězec[, od kolikátého znaku začít[, srovnávací metoda]])
. - Jak řetězce porovnávat: lze nastavit příkazem Option Compare {Binary | Text | Database}: binárně, textově (bez ohledu na velikost písmen) nebo databázově (poslední je určeno jen pro Access). V InStr a dalších funkcích lze nastavovat přímo parametrem.
- Porovnávání řetězců, který je „větší“ (například pokud jde o abecední pořadí): funkce StrComp. Syntaxe:
hodnota = StrComp(řetězec1, řetězec2[, srovnávací metoda])
. Vrací -1, pokud řetězec1 < řetězec2, 0 pokud řetězec1 = řetězec2, 1 pokud řetězec1 > řetězec2. Příklad:hodnota = StrComp("cba", "a")
MsgBox hodnota 'Vrací 1, protože cba je větší než a. - Skládání řetězce z většího počtu stejných znaků: pokud chceme řetězec s větším počtem stejných znaků, hodí se funkce String. Syntaxe:
String(počet, znak)
. Příklad:MsgBox("Ahoj" & String(8, "!"))
zobrazí „Ahoj!!!!!!!!“. Ale pozor, funguje to bohužel jen na první znak, ne na celé řetězce.String(5, "asdf")
vrátí "aaaaa". Pokud chceme seskládat řetězec z většího počtu sekvencí delších než 1 znak (tak velkého, že by jeho vypsání vedlo k neúspornosti kódu), je asi potřeba použít cyklus Do Loop. - Záměna části řetězce: k tomu je vhodná funkce Replace (viz výše), ale lze také využít funkce Mid, eventuálně MidB.[6] Syntaxe:
Mid(řetězec, kolikátým znakem začít[, délka výřezu ve znacích])
. První argument udává, v čem se hledá; druhý udává, kde se začíná; třetí udává, kolik znaků (včetně počátečního) funkce vrátí; třetí argument je nepovinný: pokud není zadán, funkce vrátí celý zbytek řetězce od znaku, kterým se má začít. Funkce má minimálně dvojí použití: 1.) Obyčejné načtení části řetězce:Retezec = "No nazdar": MsgBox Mid(Retezec, 4, 6)
zobrazí „nazdar“. Pokud není třetí argument zadán, vrací všechny od znaku určeného druhým argumentem až do konce řetězce. 2.) Přepisování části řetězce (udělá se tak, že se položí mezi hodnotu Mid a nějaký řetězec rovnítko). Např.Retezec = "Toto je dobrý text.": Mid(Retezec, 9, 5) = "divný"
přepíše řetězec do podoby „Toto je divný text.“ Pokud se třetí argument nezadá, přepíše se tolik znaků, kolik činí délka přiřazeného řetězce (ve znacích). Pokud by sahal až na konec původní délky řetězce, nepřekročí ji, nýbrž se uřízne:Mid(Retezec, 9) = "velmi podivný"
přepíše v uvedeném příkladu řetězec na „Toto je velmi podiv“. Pokud je zadán druhý i třetí argument a délka přiřazeného řetězce přesahuje počet znaků určený třetím argumentem, uřízne se opět přiřazený řetězec:Mid(Retezec, 9, 5) = "podivný"
přepíše řetězec na „Toto je podiv text.“ - Pokud se použije Mid$, funkce vrátí výsledek jako String. Jinak jako Variant.
- Makro na testování Mid: MidFunctionTestování mezi mými makry (jediný účel je ten, aby se pokaždé nemuselo všechno znovu vypisovat, když si to chce člověk otestovat).
- Funkcí Mid nelze části řetězce vyřezávat, jen nahrazovat. Vyřezávat je nutné dělat přes Replace (eventuálně přes skládání Left a Right, ale je zbytečné to dělat tak komplikovaně).
- Převod řetězce s oddělovači do pole: od VB 6 je dostupná funkce Split; prvním parametrem je převáděný řetězec, druhým oddělovač. Druhý parametr je volitelný; pokud není zadán, použije se mezera.
retezec = "já,ty,on,ona,ono"
. Split funguje až ve VBA 6, tj. od Office 2000. Pokud chcete docílit lepší kompatibility, tak Split nepoužívejte a pomozte si jinak – postupným načítáním pomocí InStr v cyklu Do ... Loop.
pole = Split(retezec, ",") - Převod pole do řetězce s oddělovači: od VB 6 je dostupná funkce Join; prvním parametrem je převáděné pole, druhým oddělovač. Druhý parametr je volitelný; pokud není zadán, použije se mezera. Příklad:
retezec = Join(pole, ", ")
. Pokud chcete docílit lepší kompatibility, používejte klasické zřetězení, například:For i = 0 to UBound(pole): soupis = soupis & pole(i) & "|": Next
. Join funguje až ve VBA 6, tj. od Office 2000. - Je řetězec čistě písmenný? To se dá zjistit přes funkci API IsCharAlpha, ale také mojí funkcí IsAlpha mezi makry.
- Je řetězec čistě alfanumerický? To umí zjistit funkce API IsCharAlphaNumeric, ale taky moje funkce IsAlphaNumeric mezi makry.
Konverzní funkce
- Val(řetězec): konverze hodnoty řetězcového typu na hodnotu numerického typu. Funkce sama eliminuje mezery. Pokud nelze hodnotu převést, vrací se hodnota -1.
- Str(výraz): konverze numerického výrazu na String. Vstupním výrazem může být i datum, ale ne například výraz jako Date & "asdf...99".
- Hex(číslo): vrací odpovídající číslo šestnáctkové soustavy.
- ChrW(číslo): vrací znak Unicode odpovídající zadanému číslu v tabulce Unicode.
- Asc(řetězec): vrací kód ANSI prvního znaku v řetězci.
- AscW(řetězec): vrací kód Unicode prvního znaku v řetězci.
- CBool(výraz): převádí do hodnoty Boolean.
- CInt(výraz): převádí do Integer.
- CLng(výraz): převádí na Long.
- CSng(výraz): převádí na Single.
- CVErr(výraz): převádí z čísla na kód chyby (Variant podtypu Error). Blíže viz nápovědu.
- Další zdroje: nápověda pod Type Conversion Functions a pod Format Function.
Řetězcové konstanty
- Zalomení řádku, tj. Chr(13): vbCr.
- Zalomení řádku a linefeed: vbCrLf. Kombinace Chr(13) a Chr(10).
- Měkké zalomení řádku: Chr(11).
- Tvrdá mezera: Chr(160).
- vbNullChar: Chr(0).
- vbTab: tabulátor.
Znaky: Chr, ChrW
- Funkce Chr vrací znak, jehož kód ASCII jí byl předán jako parametr. Syntaxe: Chr(kód znaku), kde kód znaku je číslem mezi 0 a 255. Např. znak (c) má parametr 169.
- Funkce ChrW vrací znak UNICODE. Syntaxe: ChrW(kód znaku).
- VB a HTML: zápis do HTML typu &# 8220; odpovídá znaku ChrW s příslušným argumentem, v našem případě ChrW(8220). (Proto se může hodit několik kódů vypsaných na stránce Fonetické abecedy v jazykových slovnících a v HTML.)
- Jak zjistit kód: Viz nápovědu VBA pod heslem Character Set. Tam jsou ale vypsány jen znaky do 255 (ASCII). Ta ale obsahuje jen znaky do 255. Můžeme nicméně použít jednoduché makro, které nám tabulku parametrů funkce ChrW vypíše do wordovského souboru. Takové makro najdete mezi makry pod názvem ChrWVypis. Tamtéž je i makro ChrWOznačenéhoZnaku, které ukáže argument funkce ChrW, který odpovídá označenému znaku, a ChrWZadejČíslo, které napíše znak, který odpovídá uživatelem zadanému argumentu.
- Několik vybraných znaků:
- Zalomení řádku: vbLf, respektive kompletní VbCrLf, které je ekvivalentem Chr(13) & Chr(10).
- Měkké zalomení řádku, odpovídající <br> v HTML: Chr(11).
- Anglické uvozovky: Chr(34). Když chce člověk v kódu napsat znak uvozovky, tak může napsat dvakrát tolik uvozovek, než kolik má být např. zobrazeno v MsgBox, nebo přiřetězovat Chr(34).
- České uvozovky: 8222 a 8220.
- Řecký středník („tečka uprostřed linky“): 903.
- Španělské ñ: 241.
- ẽ: 7869.
- ə: 601.
- ŋ: 331.
- ∫: 8747.
- †: 8224.
- Znaky International Phonetic Alphabet: Fonetické abecedy v jazykových slovnících a v HTML a tam uvedené odkazy na úplnější soupisy. Stačí si tam najít kódy a použít je jako parametry ChrW.
- Pomocí ChrW se správné znaky získají, ale to ještě nic neříká o jejich zobrazení, protože zobrazení závisí na skutečnosti, zda oněm znakům v užitém fontu odpovídá nějaká grafická reprezentace, nebo ne. Například pokud dáte
MsgBox ChrW(601) & ChrW(596) & ChrW(771)
, tak patrně uvidíte místo prvních dvou znaků otazníky (pokud nemáte Windows neobvykle nastavená). MsgBox totiž myslím používá ve výchozím nastavení písmo sans-serif, a v tomto fontu dvěma prvním znakům, jak vidno, nic smysluplného neodpovídá.
Konkrétní tipy a triky týkající se řetězců
Úsporný zápis nahrazení řetězců přes Replace: užití pole
Následující příklad ukáže, jak lze nahrazování většího počtu položek v řetězci zapsat do kódu úsporně pomocí pole. O polích se dovíte víc v kapitole Pole.
knahrazeni = Array("cosi|něco jiného", "cosi2|něco jiného2") 'Sem si naskládejte jakékoli řetězce; před znak | dejte vždy to, co se má nahradit, za znak dejte, čím se to má nahradit.
For i = 0 To UBound(knahrazeni)
Polozka = knahrazeni(i)
oddelovac = InStr(Polozka, "|")
co = Left(Polozka, oddelovac - 1)
zaco = Mid(Polozka, oddelovac + 1)
Retezec = Replace(Retezec, co, zaco)
Next
Tento kód lze využít i k nahrazení zpátky, stačí prohodit proměnné co a zaco.
Pole
- Funkce pole (Array) seskupuje proměnné či hodnoty do širšího celku a jednotlivé prvky opatřuje indexem.
- Dimenzování pole: pomocí klíčového slova Dim. Příklad:
Dim slova(max) As String
. Závorky jsou důležité; indikují, že jde o pole, ne obyčejný řetězec. Pokud se nezadá maximální hodnota indexu (která může mít i podobu proměnné, jež se naplní obsahem teprve při běhu makra), tak je teoreticky neomezená. - Pole ale není nutné deklarovat. Stačí ho inicializovat vložením hodnot.
- Naplnění statického pole:
osoby = Array("já", "ty", "on", "ona", "ono")
. - Přidání prvku do pole:
Pole(0) = "já"
atd. Ale pozor, v případě užití dynamického pole je třeba nejdřív určit jeho indexový rozsah. Indexový rozsah je možné určit u klíčového slova Dim, např.Dim pole(19)
, nebo lze použít ReDim:Dim pole(19)
. ReDim se používá zejména tam, kde rozsah zjišťujeme teprve při běhu. Pokud není indexový rozsah předem určen, dodání prvku, např.pole(0) = "cosi"
, dojde k chybě „Subscript out of range“. - Indexy: indexy se přidělují od 0. Lze to přenastavit, ale většinou se to nedělá a pracuje se s výchozím nastavením VB, kde je první index 0.
- Nastavení dolní meze indexového rozsahu: pomocí Option Base lze přenastavit z hodnoty 0 na hodnotu 1.
- Nejvyšší index v poli: zjistí se pomocí funkce UBound:
UBound(pole)
. - Nejnižší index v poli: zjistí se pomocí funkce LBound:
LBound(pole)
. - Použití polí: je velmi široké. Například pro úsporné přidávání do kolekce pomocí cyklu. Za příklad vděčím Petru Pecháčkovi (http://officir.web3.cz).
Dim Kolekce As New Collection
Pole = Array("já", "ty", "on", "ona", "ono")
For i = 0 To UBound(Pole)
Kolekce.Add Item:=Pole(i)
Next i - Zrušení pole: příkazem Erase (syntaxe
Erase pole
) se vyprázdní paměť zabíraná polem. Pro jeho další použití je pak nutno nově nastavit velikost pomocí ReDim nebo (v případě statického pole) je znovu inicializovat vložením hodnot. - Filtrované načtení pole do nového pole: je možné pomocí funkce Filter. Syntaxe:
NovéPole = Filter(zdrojové pole, řetězec[,prvky obsahující řetězec zahrnout[, srovnávací metoda]]
. Bližší vysvětlení argumentů: Zdrojové pole: pole, ze kterého chceme prvky načíst do pole nového. Řetězec: řetězec, jehož obsaženost či neobsaženost v položce zdrojového pole tvoří podmínku zahrnutí či nezahrnutí do nového pole. Zahrnout: pokud se všechny prvky zdrojového pole obsahující Řetězec do nového pole vložit mají, dáme True (ale to nemusíme zadávat, protože je to výchozí); pokud se mají naopak vynechat a zahrnout se mají všechny ostatní, dáme False. Funguje to i na WSH. Příklad:
vnitrniinfo = Array("tajné1", "středně tajné 1", "přísně tajné 1", "veřejné1", "tajné2", "veřejné2")
zverejnitelne = Filter(vnitrniinfo, "tajné", False)
zverejnitelne = Join(zverejnitelne, ", ")
MsgBox zverejnitelne - Spojení více polí do jednoho: nelze je prostě zřetězit pomocí operátoru &, ale je možné spojit všechna pole (např. pomocí Join) do řetězce s dostatečně distinktivním oddělovačem, spojit tyto řetězce pomocí & a pak dlouhý řetězec rozdělit pomocí Split do pole. Příklad:
knahrazeni1 = Join(knahrazeni1, "|")
knahrazeni2 = Join(knahrazeni2, "|")
knahrazenicelk = knahrazeni1 & knahrazeni2
knahrazenicelk = Left(knahrazenicelk, Len(knahrazenicelk) - 1)
knahrazenicelk = Split(knahrazenicelk, "|")
Pozor na poslední prvek pole: byl by jím prázdný řetězec, kdybychom řádkemknahrazenicelk = Left(knahrazenicelk, Len(knahrazenicelk) - 1)
poslední oddělovač nevyřadili. Alternativní postup je pak pracovat jenom s UBound - 1, ale pozor, ať na to nezapomenete. - Převod řetězce na pole o jednom prvku: snadné.
pole = Array(retezec)
, ale název se i může shodovat:cosikdesi = Array(cosikdesi)
. Někdy se to může hodit, například kdyby bylo nutné zbytečně kód větvit pro případ, že je funkci předána proměnná jako řetězec, a pro případ, že je předána jako pole. Tam pak stačí řádekIf Not IsArray(promenna) Then promenna = Array(promenna)
a je hotovo. - Častá chyba u používání polí: častá chyba je ta, že v cyklu
For i = 0 To UBound(pole)
zapomeneme, žei
je jen číslo, a pracujeme s ním v kódu, jako by obsahovalo prvek pole. Prvek je alepole(i)
, nikoli pouhéi
. Je to jasné, ale leckdy se na to zapomene a vede to k chybám. - Jak otestovat, zda není pole prázdné: pomocí porovnání LBound.
Kolekce
Kolekce obecně
- Kolekce je objekt, který drží pohromadě prvky stejného typu, obyčejně jiné objekty, ale klidně i řetězce. Na řetězce je ale lepší používat pole. Vůbec platí, že kde stačí pole, je lepší pracovat s polem.
- Vytvoření kolekce: kolekce se musí dimenzovat, v záhlaví nebo kdekoli v kódu před prvním použitím kolekce, a to takto:
Dim SeznamAdresaru As New Collection
. - Přidávání do kolekce: metoda Add. Příklad:
SeznamAdresaru.Add ("C:\programydz\lingea\data")
SeznamAdresaru.Add ("C:\Program Files\Lingea\data")
SeznamAdresaru.Add ("C:\David")
For Each adresar In SeznamAdresaru
MsgBox adresar
Next
Lze samozřejmě užít i klíčové slovo With:With SeznamAdresaru: .Add("cosi"): .Add("něcojiného"): End With
. - Count: metoda, která vrací počet prvků. Je-li kolekce prázdná, je Count 0.
- Metoda Item: vrací položku kolekce (objekt, řetězec...). Syntaxe
JménoKolekce.Item(n)
, kde n je pořadové číslo. Někt. kolekce sdružují název, takže tam dáváme místo pouhého pořadového čísla název. Někde se uvádí, že první prvek má index 0. To platí u polí, ale u kolekcí podle mého testování ne: první index je 1. - Poslední člen kolekce: získáme ho snadno:
posledni = kolekce.Item(kolekce.Count)
. - Předposlední člen kolekce:
predposledni = kolekce.Item(kolekce.Count - 1)
. - Hromadné přidávání do kolekce: jde pomocí pole a cyklu. Nedá se použít např.
Kolekce.Add ("q., qc."), (ChrW(224) & "q."), (ChrW(224) & "q., qc.")
. - Jak tvořit kolekci neobsahující duplicity:
- U řetězců: při každém přidání řetězec také přidávat do soupisu – běžného řetězce – a každé přidání do kolekce uzavřít do podmínky:
If InStr(1, SoupisZpracovanych, AktualniPolozka) = 0 Then kolekce.Add AktualniPolozka
. - U objektů: užít operátor Is a za pomoci cyklu porovnat aktuální objekt se všemi, které již byly do kolekce přidány.
- Kolekci si nelze jen tak zobrazit v MsgBox. Je nutné si ji vepsat do řetězce po jednotlivých položkách a pak si zobrazit tento řetězec.
- Jak si prvky kolekce naskládat do jedné proměnné: ukážeme si na příkladu zabudované kolekce FileConverters – převaděčů souborů ve Wordu.
Set konvertory = FileConverters
For Each konvertor In konvertory
seznam = seznam + konvertor + vbCrLf
Next
MsgBox seznam
Zabudované kolekce
- VB obsahuje mnoho zabudovaných kolekcí. Píše se o nich v těch kapitolách, kam tematicky patří.
- Vlastnosti WshCollection: Item vrací prvek z kolekce podle indexu. Length vrací počet prvků v kolekci, lze též Count (Length implementováno kvůli kompatibilitě s Jscriptem).
Set collArgs = Wscript.Arguments
For i = 0 To collArgs.Count - 1
Wscript.Echo collArgs.Item(i)
Next
Cykly a podmínky
Obecné a základní informace
- Tok: kód se vykonává v určitém pořadí; tomu se často říká tok. V jednoduchých skriptech se vykonává shora dolů, v těch složitějších bývá větvení, cyklování a volání funkcí a procedur.
- Cykly: segmenty kódu, které slouží k tomu, aby se něco vykonávalo opakovaně, např. dokud platí nebo neplatí nějaká podmínka.
- Rekurze: funkce či procedura může volat i sama sebe (tzv. rekurzívní volání), což lze výborně využít. O rekurzi se píše níže.
- Vnoření cyklů: do bloku či cyklu můžeme vnořit další blok či cyklus. Je to důležitý programovací nástroj.
- Proměnná v cyklu, jak to funguje: následující příklad ukazuje cyklus, ze kterého se nevyskočí, dokud uživatel do InputBox něco nezadá.
Do
jmeno = InputBox("Zadejte své jméno:")
Loop Until jmeno <> ""
Lepší je ale umožnit po několika pokusech vyskočení (nebo skončit automaticky). - Nekonečný cyklus: je velmi nežádoucí. Bývá proto dobrým zvykem vytvořit si proměnnou, která zachytává počet otočení cyklu, a když to překročí určité číslo, tak cyklus ukončí. Jak na to? Před začátek cyklu (před Do apod.) jí přiřadit nulu:
pocetKol = 0
. Pak dát dovnitř cyklu toto:pocetKol = pocetKol + 1
. Pak někam do cyklu dátIf pocetKol > 5 Then Exit Do
. Tak zajistíme, že cyklus proběhne maximálně pětkrát. Tuto podmínku lze také dát přímo k Do či Loop:Loop While pocetKol < 5
. Nebo lze samozřejmě naprogramovat cyklus tak, aby se ani bez této pojistky nikdy nemohl stát nekonečným.
Do ... Loop
- Cyklus určený pro opakování bloku příkazů v závislosti na splnění podmínky. Má dvě formy. Jedna dává podmínku, za které se má kód vykonávat, k Do (tam, kde např. chceme, aby za určitých okolností cyklus vůbec neproběhl), druhá k Loop. Podmínka se konstruuje pomocí slova While či Until. While říká: vykonávej, dokud platí podmínka. Until říká: vykonávej, dokud nezačne platit podmínka.
- Syntaxe:
Do [{While | Until} podmínka]
[příkazy]
[Exit Do]
[příkazy]
Loop - Druhá forma:
Do
[příkazy]
[Exit Do]
[příkazy]
Loop [{While | Until} podmínka] - While a Until: člověk si lépe uvědomí význam, když bude While překládat jako „pokud“ (tj. např.: vracej se, pokud je hodnota proměnné True). Until je nejlepší překládat jako „dokud ne“ (tj. např. vracej se, dokud hodnota není True).
- Podmínka While na začátku cyklu: syntaxe
Do While podmínka
umožní, aby cyklus neproběhl ani jednou: například je-li zdrojový soubor prázdný, nemá smysl z něj něco načítat do dialogového okna. Vyhodnotí-li se podmínka cyklu Do While na False, cyklus se neprovede a předá iniciativu řádku, který bezprostředně následuje za příslušným řádkem Loop. Osamocené Do jasně vypovídá, že cyklus proběhne alespoň jednou. Do While ne. - Ukončení cyklu Do: pomocí Exit Do v jakémkoli místě kódu.
- Do ... Loop bez podmínky: lze zadat prostě Do ... Loop a neuvést žádnou podmínku. Podmínku lze v takovém případě „skrýt“ do nitra cyklu v podobě
If podmínka Then Exit Do
. Bez ukončující podmínky vzniká nekonečný cyklus, což je pochopitelně nežádoucí.
While ... Wend
- Jednodušší obdoba Do ... Loop. Po While je nutné napsat podmínku. Zachovává se z historických důvodů. Upřednostňuje se užívání Do ... Loop.
If ... Then ... ElseIf ... Else ... End If
- If podmínka Then ... [ElseIf] ... [Else] ... End If je nejběžnější větvení určené k vykonání bloku kódu za splnění určité podmínky. ElseIf a Else jsou volitelné. End If se naopak v blokovém If vynechat nesmí. Za ElseIf se může specifikovat další podmínka. Za Else se dává, co se má udělat, pokud není podmínka za If ani žádným z ElseIf splněna. Příklad:
JmenoUzivatele = InputBox("Napište prosím své jméno:")
JmenoUzivatele = Trim(JmenoUzivatele)
If JmenoUzivatele = "" Then
Pozdrav = "Vítejte."
ElseIf IsNumeric(JmenoUzivatele) Then
Pozdrav = "Roboti jsou samozřejmě taky vítáni."
Else
Pozdrav = "Vítejte, " & JmenoUzivatele & "."
End If
MsgBox Pozdrav
"" je řetězec nulové délky. Kdybychom neužili větvení, tak se objeví i v případě nezadání s čárkou a tečkou, ale beze jména. Na všech větvích se zde přiřazuje do proměnné Pozdrav. Můžeme se vnořit či za End If přidat další blok: pokud se jméno uživatele rovná DavidThen Pozdrav = Pozdrav & " Víte, že máme stejné jméno?"
. - Jednořádkové If ... Then: jednořádková podmínka If ... Then se neukončuje pomocí End If – to je jen pro blokové If. V jednořádkovém If ... Then lze použít i Else. Naopak není možné v jednořádkovém zápisu použít ElseIf.
- ElseIf: velmi užitečné. Užívá se jen v blokovém If a syntaxe je následující:
If podmínka Then
udělej něco
ElseIf podmínka 2
udělej něco jiného
ElseIf podmínka 3
udělej ještě něco jiného
Else
udělej ještě něco jiného
End If - Chyba „End If withnout block If“: někdy k ní dochází ne kvůli chybějícímu If, ale proto, že v některém cyklu Do ... Loop, vnořeném do If ... End If, chybí Loop či že ve vnořeném Select Case chybí End Select; je potřeba na to myslet.
- Vícečlenná podmínka: lze samozřejmě užívat více podmínek, které se uvádějí do vztahu pomocí operátorů:
If (Left(nazevOkna, 2) = "ms") Or (Left(nazevOkna, 2) = "ma") Then
atd. Nedává se nějaké Or If apod. Mimochodem, poznáte, co je na uvedeném kódu nedokonalé?[7]
Select Case
- Select Case: blok podobný If ... Then; je určen k provedení akce v závislosti na hodnotě proměnné či na návratové hodnotě funkce. Syntaxe:
Select Case Výraz
Case Výsledek1
Blok 1
Case Výsledek2
Blok2
[Case Else]
BlokElse
End Select
Case Else je volitelné. - Příklad použití najdete v makru KlávesnicePřepínač mezi makry.
- Použití Select Case na ošetření chyb: možné chyby se mohou vypisovat do řetězce If ... Else a zde se jim přiřazují konkrétní chybová hlášení a ošetření. Ještě lepší ale asi je umístit ošetření chyb na jedno místo kódu a použít Select Case Err.Number.
For ... Next, For Each ... Next
- Cyklus For ... Next je určen k vykonání bloku kódu pro každý člen určité množiny. Tuto množinu buď můžeme mít předem (může jí být například kolekce všech souborů v adresáři), nebo ji můžeme vytvořit přímo na začátku cyklu For ... Next.
- For Each ... Next: pokud pracujeme s kolekcí, použijeme For Each ... Next. Například:
For Each soubor In adresar.Files
Proměnná soubor nemusí být nikde deklarovaná; z této syntaxe je stroji VB zřejmé, že soubor zastupuje pokaždé jednu položku z adresar.Files. - For ... To ... Next: pokud chceme stanovit číselný rozsah, použijeme For ... To ... Next. Syntaxe je
For i = cislo1 To cislo2
'Sem přijde kód, co se má udělat
Next
Příklad na počítání, kolik prvků pole je čistě číselných:
pocetCiselnych = 0
For i = 0 to UBound(pole)
If IsNumeric(pole(i)) Then pocetCiselnych = pocetCiselnych + 1
Next - Vyskočení z cyklu: Exit For.
- Pro přehlednost lze za Next napsat název parametru uzavíraného cyklu – například místo Next napsat Next i. Zvlášť u dlouhých a vnořovaných cyklů se to hodí. Na funkčnost to nemá vliv.
- Příklad – výpis speciálních složek Windows přes WSH:
seznam = "Speciální složky: " & vbCrLf
For i = 0 To specslozky.Count - 1
seznam = seznam & specslozky(i) & vbCrLf
Next
MsgBox seznam
Nejdříve je samozřejmě nutné získat odkaz na složky:
Set ws = Wscript.CreateObject("Wscript.Shell")
.
Set specslozky = ws.SpecialFolders - For Each ... Next: vykoná tělo cyklu pro každý prvek kolekce nebo pole. For Each parametr In skupina TěloCyklu Next. Parametr je proměnná, které jsou postupně přiřazovány jednotl. prvky objektu Skupina.
- Vyskočení z cyklu For: pomocí příkazu Exit For.
With ... End With
- Příkaz With (který není cyklem, ale obvykle se pod kapitoly cyklům věnované řadí) uvozuje blok seskupující příkazy (metody, vlastnosti atd.), které v tečkové notaci sdílejí počáteční část. With přispěje k zpřehlednění kódu a zrychlí jeho vykonání.
- Příklad:
With Selection.Find
.text = "něco"
.Replacement.text = "něco jiného"
.Forward = True
.Wrap = wdFindContinue
.Execute Replace:=wdReplaceAll
End With - Jiný příklad:
With MojeKolekce
.Add("prvek1")
.Add("prvek2")
End With - With ... End With lze zanořovat do jiných bloků With ... End With.
Podprogramy (procedury a funkce)
Procedury
- Podprogramy: důležité prvky. Ve VBS a VBA jsou dva druhy podprogramů: procedury a funkce. Procedury provádějí akce. Funkce provádějí akce a vracejí hodnotu. Uvnitř funkcí a procedur nemůže být další podprogram, ale další podprogram z nich lze volat.
- Syntaxe:
Sub
'sem přijde kód
End Sub - Procedura: procedura je pojmenovanou posloupností příkazů. Má začátek a konec. Její průběh lze ovlivnit předanými parametry. Nemůže obsahovat jinou proceduru či funkci, ale může je volat. Může volat i sama sebe (tzv. rekurzívní volání).
- Jak nazývat proceduru: obvykle se doporučuje začínat ji slovesem. Nicméně pokud něco lépe indikuje oblast použití či slouží k lepší přehlednosti, není dobré se toho držet. Příklad: pokud začnete mezi dvěma sty maker název nějakého makra řetězcem Vymazat, tak je to málo distinktivní, protože tak může začínat spousta maker; vhodnější je makro nazvat StylyNepoužitéVymazat. Takže doporučuji začínat slovesem jen tam, kde je to opravdu zváženo jako vhodné, ne všude.
Funkce
Nevestavěné funkce
- Funkce je podprogram, který provádí akci a vrací hodnotu.
- Syntaxe:
Function
'sem přijde kód
End Function - Příklad funkce:
Function JednaTretina(x)
JednaTretina = x / 3
End Function - Jak se tato funkce zavolá: y = JednaTretina(x). Podrobněji se o volání píše níže.
- Volání funkce: funkci je možné volat z procedury i z jiné funkce. O volání funkcí a procedur viz níže speciální podkapitolu.
- Jak funkci zapsat do modulu, např. modulu NewMacros wordovské šablony Normal: nikoli do nitra nějaké procedury, nýbrž samostatně: Function ... End Function.
- Implicitní hodnota nepovinného parametru funkce: k určení implicitní hodnoty se využívá přiřazení přes rovnátko v deklaraci funkce. Argument je označen klíčovým slovem Optional. Pokud není do funkce dodán, tak je mu automaticky přiřazena hodnota z deklarace. Lépe to ukáže příklad:
Function Funkce(Optional p = "neco")
. Zda byl argument předán, nebo se použila implicitní hodnota, lze zjistit pomocí IsMissing, ale pozor, funguje jen na datový typ Variant, takže pokud deklarujete třeba As Integer, nebude IsMissing fungovat správně. - Deklarace datového typu argumentu: do deklarace funkce či procedury lze vložit také deklaraci datového typu procedury, např.
Function Nahradit(co As String, zaco As String, Optional kolikrat As Integer = Empty)
. Ale dejte si potom pozor na testování, zda byl parametr dodán, protože IsEmpty a IsMissing funguje správně jen s proměnnou typu Variant, u všech ostatních vrací oboje False. Potvrzuje to i nápověda. Takže když do deklarace funkce dáte např.Optional kolikrat As Integer = Empty
a pak testujete kolikrat přes IsEmpty (If IsEmpty(kolikrat) Then
atd.), nedostanete správný výsledek; IsEmpty vrací takto vždy False. Je potřeba testovat jinak, přes rovnítko:If kolikrat = Empty Then
; to funguje, ověřeno. - Funkce lze spouštět pomocí událostí. Víc informací najdete v nápovědě pod Event.
- Jak nazývat funkci: obvykle se doporučuje začínat ji slovesem. Nicméně pokud něco lépe indikuje oblast použití, není potřeba se toho držet.
Vestavěné funkce
- VB má mnoho vestavěných funkcí. Rozebírají se pod jednotlivými kapitolami, kam tematicky patří.
- $: některé vestavěné funkce mají dvě mutace, např. Mid a Mid$. Ta se znakem dolaru vrací hodnotu typu String, ta bez znaku dolaru hodnotu typu Variant.
Volání funkcí a procedur a předávání argumentů
- Lze užít několik způsobů zápisu. Nejsou ve všech případech zcela ekvivalentní. Buď prosté napsání názvu funkce do kódu, nebo příkaz Call, nebo (ve VBA) metoda Run objektu Application (příklad: Application.run macroname:="MojeMakro"). Application.Run funguje i tehdy, když není funkce v témže modulu. To je výhodné např. u maker, které jsou dodávány s některými programy a které mají vlastní wordovskou šablonu. Zavolání pomocí Call tam povede k chybě, kdežto Application.run bude fungovat. Ale všude, kde k chybě nedochází, je lepší používat Call či přímý zápis.
- Call: výhoda příkazu Call oproti přímému zápisu je ta, že pomocí Ctrl+F snadno najdeme všechny funkce a procedury, které kód volá; nemusíme je hledat očima. U Call je potřeba dát si pozor na syntaxi; Call vyžaduje při předávání argumentů závorky. Ověřeno například, že zápis
Podadresare adresar, filtr
WSH bere, kdežto pokud dáme Call, tak dochází k chybě, dokud argumenty neumístíme do závorky:Call Podadresare(adresar, filtr)
; tuto zvláštnost při použití Call potvrzuje i nápověda. - Voláním vlastních funkcí si lze významně doplnit zabudované možnosti VB o nové, užitečné postupy. Můžete se například podívat na funkce IsAlpha či IsAlphaNumeric mezi mými makry – doplňují dvě důležité funkce, které ve VBA 6 chybějí.
- Předávání argumentů funkci či proceduře: funkci či proceduře lze předávat argumenty, což zajišťuje potřebnou pružnost a použitelnost funkce v mnoha souvislostech.
- Jak předat argument: argument se předává tím, že se prostě napíše vedle volání, a to přímo za mezeru (pokud voláme funkci bez použití příkazu Call) nebo do závorek (pokud voláme pomocí Call). Název argumentu se nemusí krýt s názvem uvedeným v deklaraci funkce.
- V závorce v deklaraci funkce musí být deklarován i argument, pokud chceme, aby byl funkci předán. Argumentů může být i víc; dělí se čárkami. Každý z nich může mít specifikovaný datový typ. Deklarace pak vypadá například takto:
Public Function Nahradit(co As String, zaco As String, MaxPocetNahrazeni As Integer)
. - Další informace: viz nápovědu pod Function Statement, Declare Statement, Sub Statement.
- Syntaxe volání: pokud se použije příkaz Call, je nutné dát argumenty do závorek. Pokud se funkce volá bez něj, je nutné závorky naopak nedávat. Pokud se ale volání přiřazuje rovnítkem k nějaké proměnné (do které chceme zapsat návratovou hodnotu funkce), tak tam závorky jsou (a příkaz Call v takových případech užít nelze). V příkladu uvedeném níže se volá funkce VynasobDvema
vysledek = VynasobDvema(cislo)
. Pokud se předává víc argumentů, dělí se čárkami. - Pokud funkce něco vyhodnocuje, je třeba použít pro zapsání návratové hodnoty její název. Hodnota by sice šla předat i tím, že by se zapsala do některého z předaných argumentů, ale to je ve většině případů nekorektní (a nesmyslné). Použití ukazuje níže uvedená funkce VynasobDvema, kde se v rámci volané funkce píše:
VynasobDvema = 2 * i
. Kdyby se do ní dalovysledek = 2 * i
, tak funkce sama o sobě bude fungovat stejně dobře, jenže nepředá návratovou hodnotu proceduře (a právě o předání návratové hodnoty nám jde). - Předávání nejlépe osvětlí názorný příklad:
Function VynasobDvema(i)
VynasobDvema = 2 * i
End Function
Tuto funkci pak zavoláme, například z wordovského makra (které je procedurou):
Sub NasobiciProcedura()
cislo = InputBox("Zadejte číslo, které se má vynásobit dvěma.")
MsgBox VynasobDvema(cislo)
End Sub
Tento příklad je určen k co nejjednoduššímu osvětlení; sám o sobě je samozřejmě k ničemu, protože se to dalo řešit mnohem úsporněji hned v rámci procedury NasobiciProcedura. Ale smysl to mít začne tam, kde by bylo zbytečné a neúsporné vypisovat opakovaně totéž, a také samozřejmě u používání rekurze, kde procedura či funkce volá sama sebe tak dlouho, dokud je potřeba. - Další příklad lze najít v nápovědě pod Passing Arguments Efficiently.
- Příklad použití – jednoduchá nahrazovací funkce: sestavíme si, například v modulu NewMacros wordovské šablony Normal, následující funkci:
Function Nahradit(co, zaco)
'Jednoduchá nahrazovací funkce přes Selection.Find, které mohou různé procedury
'předávat hodnoty proměnných co a zaco.
'MatchCase = False).
Selection.HomeKey unit:=wdStory
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
With Selection.Find
.text = co
.Replacement.text = zaco
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute Replace:=wdReplaceAll
End With
End Function
Pak stačí v kterémkoli makru napsat pouze napříkladNahradit "Dobrí den", "Dobrý den"
k tomu, aby se všechny sekvence „Dobrí den“ v dokumentu nahradily za „Dobrý den“. Je jasné, kolik znaků kódu ušetří toto efektivní využívání volání. Pozn.: Jak jste si určitě všimli, nezískáváme tu žádnou návratovou hodnotu, takže by stejně dobře šlo použít proceduru: místo Function by bylo Sub, místo End Function by bylo End Sub. V tomto případě vlastně není důvod, proč z toho dělat funkci (ale taky se tím nic nezkazí). Funkce by ovšem přišla ke slovu tam, kde bychom například chtěli sledovat počet nahrazení. Funkce se nezobrazují v aplikacích Office v okně Makra, takže někdy je lepší vést něco, na co by stačila i procedura, jako funkci, protože zobrazení v okně Makra by jen mátlo či vedlo i k vážným chybám (například funkce na odstranění diakritiky, která má být podmíněna návratovou hodnotou vbYes od uživatele ve volající proceduře, by se takto dala spustit i přímo a bez varování by odstranila diakritiku v celém dokumentu). - Návratovou hodnotou funkce mohou být nejrůznější typy dat. Například má funkce GetFiles, kterou najdete mezi makry, vrací pole obsahující všechny soubory adresáře, který je funkci předán jako parametr.
- V deklaraci funkce je možné uvést datový typ argumentu. Myslím, že pokud argument do funkce jako daný datový typ nevstupuje, tak je na něj převeden – bylo by nesmyslné, kdyby tomu bylo jinak – ale neověřoval jsem to.
- ByVal: klíčové slovo ByVal v deklaraci podprogramu zajistí, že si podprogram pořídí kopii předávaného argumentu a hodnotu původního argumentu nezmění. Příklad:
Function Factorial (ByVal cislo As Integer)
; bližší osvětlení viz v nápovědě pod Passing Arguments Efficiently. - Příklad, kde procedura předává proměnnou funkci, ta proměnnou změní a předá ji zpět proceduře:
Function ZměňZprávu(zprava)
MsgBox "Nyní je zpráva následující: " & zprava & ". Ale teď ji změníme."
zprava = "Nashledanou"
End Function
Sub zk()
pozdrav = "Dobrý den"
Call ZměňZprávu(pozdrav)
MsgBox "Nová hodnota: " & pozdrav
End Sub
Pozn.: Vyřazování argumentu (výrazu v závorce) vede k chybám: přestávají si jej správně předávat. - Kde získat další informace o předávání argumentů: v nápovědě pod Calling Sub and Function Procedures, Passing Arguments Efficiently.
- Rekurze: rekurze je důležitý programovací nástroj, který pracuje na jednoduchém principu: podprogram volá sám sebe, ale předávají se mu parametry s novými hodnotami. Více se o tom dovíte v podkapitole Rekurze.
- Spouštění skriptů z jiných skriptů: je bez problémů možné pomocí metody Run objektu Wscript.Shell. Příklad:
Set wshshell = Wscript.CreateObject(""Wscript.Shell"")
wshshell.Run("C:\skript.vbs")
Skript si lze dokonce z jiného skriptu dynamicky vytvořit (viz kapitolu Textový soubor, kde se uvádí, jak tvořit textové soubory) a pak ho pomocí Run spustit; to se někdy může velmi hodit. - Přímé předávání argumentů jiným skriptům není myslím možné. Je nutné předat je nepřímo, například zapsat hodnoty do textového souboru a v druhém skriptu je ze souboru načíst. V rámci jednoho skriptu ale normálně funguje výše popsaný postup volání.
- Připomínám, že procedura provádí akce, funkce provádí akce a vrací hodnotu. Proto pokud chcete návratovou hodnotu, použijte funkci.
Rekurze
- Rekurze je postup, kde podprogram (tj. ve VB procedura či funkce) volá opakovaně sám sebe tak dlouho, dokud je potřeba, ovšem se změněným parametrem. Jde o mocný programovací nástroj. Program vypisující obsahy adresářů např. pro každý z nalezených podadresářů zavolá sám sebe a pokračuje tak dlouho, dokud nenarazí na složku, která již žádné podadresáře nemá.
- Jak se postupuje: v deklaraci podprogramu se uvede jeden či více argumentů a do samotného podprogramu se pak vepíše volání tohoto stejného podprogramu a na tomto řádku se pošlou podprogramu nové argumenty. Příklad, kde máme proceduru na zjištění podadresářů aktuálního adresáře a kde také voláme samostatnou proceduru SouboryAPripona, která vypisuje všechny soubory aktuálního adresáře:
Sub Podadresare(ByVal aktualniadr, pripona)
SouboryAPripona aktualniadr, pripona
Set DalsiAdresare = aktualniadr.SubFolders
For Each fld In DalsiAdresare
Podadresare fld, pripona
Next
End Sub - Jakmile člověk jednou pochopí předávání argumentů, tak se mu nakonec obvykle podaří rekurzi, kterou potřebuje, naprogramovat. Důležité je vědět, že podprogram má ve své deklaraci uvedeny argumenty, jejichž názvy se pochopitelně nemusejí krýt s názvy parametrů, které jsou do podprogramu předány. Za daný argument se v celém podprogramu dosadí hodnota příslušného parametru.
- Kde najít příklady rekurze: ve skriptu na tvoření zástupců či na vyrábění seznamu souborů (filelistu) mezi skripty.
Datum a čas
- Now: funkce Now vrací aktuální systémové datum a čas včetně sekund.
- Date: funkce Date vrací systémové datum.
- Time: vrací aktuální systémový čas včetně sekund.
- Day: vrací pořadové číslo dne v měsíci. Syntaxe:
Day(datum)
. Příklad:MsgBox Day("5. 7. 2004")
zobrazí 5. - Hour: vrací hodinu dne. Syntaxe:
Hour(čas)
. Příklad:MsgBox Hour("9:31:17")
zobrazí 9. Pokud je do funkce poslán údaj, který neobsahuje čas, vrátí 0:datum = "14. 8. 2004": MsgBox Hour(datum)
. To platí i o dalších analogických funkcích Minute apod. - Minute: analogické k Hour.
- Second: analogické k Hour.
- Month: analogické k Hour; vrací pořadové číslo měsíce v roce.
- Year: analogické k Hour; vrací rok.
- MonthName: vrací systémové jméno měsíce. Parametrem je pořadové číslo měsíce, zjištěné například pomocí funkce Month. Příklad:
MsgBox MonthName(1)
zobrazí v české instalaci Windows „leden“. - Timer: vrací počet sekund uplynulých od půlnoci jako Variant. Velmi užitečná funkce. Příklad použití:
start = Timer
'sem přijde vlastní kód
konec = Timer
TrvaniSkriptu = konec - start
MsgBox "Hotovo. Provedení skriptu trvalo " & TrvaniSkriptu & " sekund."
Timer je také užitečný pro určení maximální doby trvání cyklů: do takových cyklů se zařadí například podmínkaIf Timer - Start > 60 Then Exit Do
. - CDate: konverzní funkce, která převede řetězec obsahující datum v platném formátu na datový typ Date. Příklad:
datum = CDate(retezec)
. - Datum není obyčejný řetězec. Když se dá datum = Date, tak se tím nedostane řetězec. Datum je zvláštní datový typ. Proto když srovnáváme, musíme použít funkci DateDiff (viz níže) nebo dát např.
If Left(zmenen, zn) = Left(datum, zn)
, kde zn je Len(datum). Nebo se dá užít konverzní funkce Str. - Porovnání data: není nutné ani vhodné data srovnávat jako běžné řetězce. Je tu funkce DateDiff. Syntaxe:
DateDiff(jednotky, datum1, datum2[, první den v týdnu[, první den roku]])
. Jednotky určují, s jakými jednotkami počítáme, a může nabývat hodnot d (den), h (hodina), n (minuta), s (sekunda), m (měsíc), w (den v týdnu), ww (týden), q (čtvrtletí), y (den v roce), yyyy (rok). Poznámka: jde o hodnotu rozdílu, takže například rozdíl v datu 1. 1. 2010 12:00:00 a mezi 1. 1. 2010 13:00:00 není u jednotek "s" roven nule, nýbrž 3600. Příklad:If (DateDiff("d", datum, od) <= DateDiff("d", datum, zmenen)) Then
atd. Další příklad:
datum = soubor.DateLastModified
atd.
If DateDiff("d", datum, Now) > 15 Then
Prostým odčítáním to řešit nelze. Odčítání vrací prázdný řetězec. Následuje několik příkladů. - Pokud je soubor 1 mladší než soubor 2: následující příklad vám možná ušetří trochu přemýšlení. Znamená: pokud je soubor 1 mladší než soubor 2, tak... Počítá se sekundami („s“).
If DateDiff("s", soubor1.DateLastModified, soubor2.DateLastModified) < 0 Then
. - Pokud je soubor 1 starší než soubor 2:
If DateDiff("s", soubor1.DateLastModified, soubor2.DateLastModified) > 0 Then
. - Pokud byl soubor naposledy změněn dnes:
If DateDiff("d", Date, soubor.DateLastModified) = 0 Then
. - Den v týdnu: funkce Weekday(datum).
datum = InputBox("Zadejte datum ve formátu bez mezer, např. 1.1.2003:")
MsgBox Weekday(datum)
Funkce vrací číslo, přičemž 1 je neděle, 7 sobota atd. Pokud se dodá parametr vbMonday (např.den = Weekday(datum, vbMonday)
), tak je za 1. den v týdnu pokládáno pondělí. vbMonday je potřeba v českém počítání dodávat, jinak číslo neodpovídá, jak si můžete ověřit vyřazením vbMonday z makra CoByloZaDen mezi makry, spuštěním makra a zadáním dnešního data do InputBoxu. - Název dne v týdnu: pokud chceme systémový název dne, tak užijeme funkci WeekdayName, do které jako parametr dodáme pořadové číslo dne, zjištěné například pomocí funkce Weekday. Příklad:
den = Weekday(datum, vbMonday)
. To ověřeno, funguje, viz moje makro CoByloZaDen mezi makry. Ukazuje to den podle místního nastavení (tj. v české instalaci Windows česky).
DenSlovy = WeekdayName(den) - Připočítávání či odečítání dat: provádí se pomocí funkce DateAdd, která vrací datum vypočtené přičtením zadaného počtu uživatelem určených jednotek. Syntaxe:
DateAdd("jednotka", počet, výchozí datum)
, kde jednotkou může být d (den), h (hodina), n (minuta), s (sekunda), m (měsíc), w (den v týdnu), ww (týden), q (čtvrtletí), y (den v roce), yyyy (rok). Příklad:MsgBox("Za 90 dní bude " & DateAdd("d", 90, Date) & ".")
. (příklad DZ) - Nastavení systémového data a času: pomocí Date a Time. Přes VBScript to ale nejde.
- Jak naformátovat řetězec jako datum: funkcí FormatDateTime. Syntaxe:
FormatDateTime(datum[, formát]
, kde volitelným paramentrem formát může být jedna z těchto konstant: vbShortTime, vbLongTime, vbShortDate, vbGeneralDate. - Formát data, možnosti: viz nápovědu pod User-Defined Date/Time Formats (Format Function).
Matematické operace
- Zaokrouhlování: funkce Round se syntaxí
Round(výraz[, počet desetinných míst])
. Příklad:cislo = Round(cislo, 3)
. - Zbytek při dělení: zjistí se pomocí operátoru Mod. Syntaxe:
zbytek = dělenec Mod dělitel
. Lze také využít v podmínce. Příklad, kde je takováto podmínka začleněna do dlouhého cyklu a zajišťuje uložení dokumentu při každém tisícím průběhu cyklu:If pocetKol Mod 1000 = 0 Then ActiveDocument.Save
. - Inicializace generátoru náhodných čísel: příkaz Randomize. Pokud se zadá jako argument numerický výraz, bude inicializován touto hodnotou, pokud ne, bude inicializován hodnotou náhodnou.
- Další zdroje: nápověda pod Operator.
Běh skriptu či makra
- Jak přerušit běžící makro: kombinací Ctrl+Break.
- Jak přerušit běžící skript: vyvoláním okna Správce úloh (kombinací Ctrl+Alt+Del) a ukončením skriptu.
- Přerušení: zajišťuje příkaz Stop zapsaný do kódu. Pozastaví běh aplikace a převede ji do režimu přerušení. Výhodné pro ladění; lze si v editoru VB podržet myš nad proměnnými a zjistit jejich hodnoty, popřípadě otevřít ladicí okno a přehlédnout proměnné, nebo dále krokovat průběh programu. Pokračování lze docílit skrze Run, Continue z nabídky, tlačítkem Continue nebo klávesou F5. Samozřejmě že Stop lze zapsat do kódu podmíněně: například
If PocetKol = 12 Then Stop
použijeme, když víme, že každé dvanácté otočení cyklu pracuje chybně a chceme zjistit proč. Ve VBS Stop nefunguje. - Ukončení: ve VBA End, Exit Sub či Exit Function zapsané do kódu. Příkaz End skončí zcela, kdežto Exit Sub, popř. Exit Function, vyskočí jen z aktuální procedury či funkce. Rozdíl je patrný zejména u maker, která jsou volána jinými makry; pokud se dá End, skončí běh kódu nadobro. Pokud se dá Exit Sub, tak se vyskočí jen z aktuální procedury a pokračuje se dál. Vyzkoušeno.
- VBS: Wscript.Quit. Příklad:
If cesta = "" Then wscript.Quit
. Ukončí to celý skript. End Sub, End Function normálně ukončuje proceduru či funkci. End ve VBS nefunguje. - Vyskočení z cyklů: viz pod cykly. Exit Do, Exit For atd.
- Pauza: vykonávání kódu je možné přerušit funkcí Timer. Ta vrací počet sekund uplynulých od půlnoci, čehož lze využít; následuje adaptovaný příklad z nápovědy:
delkapauzy = 5
Start = Timer
Do While Timer < Start + delkapauzy
DoEvents
Loop - Pauza ve VBS: k tomu je určena metoda Sleep objektu Wscript se syntaxí
wscript.Sleep počet milisekund
. Pozastaví dobu vykonávání skriptu (v milisekundách). Příklad:wscript.Sleep 5000
. - Ponechání prostoru ostatním aplikacím k vykonání akcí, které vykonat chtějí: k tomu slouží funkce DoEvents. Dává se například do hodně dlouhých cyklů.
- Automaticky se zavírající zpráva či dotaz: jsou situace, kdy se chceme uživatele na něco zeptat, ale pokud neodpoví do určité doby, tak pokračovat ve vykonávání kódu. Více se o tom píše v kapitole o komunikaci s uživatelem.
- Určení maximální doby trvání skriptu ve VBS: k tomu se používá metoda TimeOut objektu Wscript:
Wscript.Timeout = 12
. Určuje maximální dobu vykonávání skriptu. - Jak počkat, až nebude aplikace zaneprázdněná: u těch aplikací, které jsou zabudované do VB, je to snadné: použijeme vlastnost Busy. Např. máme objekt mujWord (získáme ho pomocí GetObject či CreateObject, například:
Set mujword = GetObject( , "Word.Application")
) a dáme cyklus:Do While mujWord.Busy: DoEvents: Loop
. Tím docílíme, že skript počká, až nebude Word zaneprázdněn. U aplikací nezabudovaných do VB to takto nejde.
Ladění, testování, odstraňování chyb
- Viz též kapitolu Chyby.
- Základem úspěšného ladění je zjišťování hodnot proměnných a návratových hodnot funkcí, protože to nám často napoví, kde je chyba. Lze to kontrolovat přes MsgBox zařazené do kódu, nebo přes Run to cursor a podržení myši nad proměnnou, nebo konečně přes Debug.Print, které vypisuje hodnoty proměnných či návratové hodnoty funkcí do okamžitého okna (které se v editoru VB otevře pomocí Ctrl+G; je potřeba mít ho otevřené předem). Další možností je zařadit do kódu vyhotovení textového souboru, kam se vypíše protokol (zvlášť u složitých maker, kde narazíme na chybu a nevíme, v čem je, to může být velmi užitečné; soubor se tvoří metodou metodu CreateTextFile objektu FSO). Do souboru si můžeme vytvořit komplexní protokol celého makra či skriptu.
- Je dobré vyřadit při testování a ladění On Error Resume Next. To přeskakuje chyby, kdežto my chceme zvědět, jaké tam jsou, a nějak se z toho poučit a případně je ošetřit.
- U složitých maker je velmi vhodné pořizovat si v různých stádiích zálohy kódu, např. do textového souboru, a to s poznámkami, jakou fázi daná verze představuje a do jakých úprav se chceme pustit následovně. Leckdy totiž kód naše další úpravy pokazí, takže je nejlepší se vrátit k „nižší verzi“ a zkusit jinou cestu.
- K testování slouží režim Run.
- Run to cursor: hodnoty proměnných si lze zjišťovat přes MsgBox, ale asi šikovnější je přeskočit do editoru VB a pod nabídkou Debug dát Run to cursor (popř. zkratka Ctrl+F8). To provede makro až ke kurzoru a na podržení myši nad proměnnými ukáže jejich hodnoty. Popřípadě je možné vložit do kódu Debug.Print a sledovat hodnoty v okamžitém okně.
- Zjišťování hodnot pomocí Debug.Print: Pomocí
Debug.Print funkce()
či pouhého?funkce()
, zjistíme, co vrací funkce. PomocíDebug.Print promenna
, resp. pouhého?promenna
, zjistíme hodnotu proměnné. Samotné Debug.Print ale ladicí okno neotvírá; je třeba mít je otevřené. V editoru Visual Basicu se otvírá pomocí Ctrl+G. - Přerušení běžícího programu VB: lze toho docílit kombinací kláves Ctrl+Break. Pak lze vybrat, co se má udělat; pokud se vybere Debug, tak se skočí na místo v kódu, na kterém bylo vykonávání zastaveno, a lze si prohlížet hodnoty proměnných tím, že nad nimi podržíme kurzor myši.
- Někdy může být dobré vřazovat při testování možnost ukončit dlouhý cyklus:
odpoved = MsgBox("Mám skončit?", 4)
.
If odpoved = vbYes Then End - Řádky, které chceme na chvíli vyřadit z provozu, není nutné z kódu mazat. Stačí z nich udělat komentář znakem ' na začátku řádku.
- Osamostatnění bloku do zvláštní procedury: někdy může být prospěšné testovat nikoli celý skript (např. pokud provedení dlouho trvá), nýbrž jen menší blok ve zvláštním pracovním skriptu či makru. Tak můžeme mj. poznat, zda je chyba v něm, či jinde.
- Je dobré psát kód co nejpřehledněji, aby se chyba dobře hledala, a případně také v komentářích zmínit jeho slabá místa, o nichž předpokládáte, že by tam k chybě mohlo docházet.
- Při ladění může být vhodné přizpůsobit podmínky, zejména v tom smyslu, že simulujete horší podmínky, než jaké v reálu obvykle nastávají. Příklad: načítáte určité řetězce ze souborů XML a rozdělujete je do polí. Nikde ve zdrojovém dokumentu nemáte žádný výskyt určité syntaxe, kterou zhodnotíte jako potenciálně problematickou, ale chcete na ni skript vyladit. Proto si vytvoříte speciální soubor, do kterého vložíte potenciálně problematické řetězce, vymyšlené právě pro ten účel, vložíte, a ladíte skript na něm.
- Několik dalších rad pro testování a ladění:
- Nehledejte chybu jen v samotném makru. Nejednou se mi stalo, že jsem seděl nad kódem hodiny a nenašel jsem chybu a pak jsem se například podíval na zdrojové soubory, které makro zpracovávalo, a našel jsem chybu v nich.
- Chyba může být také ve volaných procedurách a funkcích. I do nich je potřeba se podívat.
- Je dobré se nezaměřit jen na segment, kde k chybě došlo, nýbrž si makro pročíst od začátku. Chyba je totiž často někde jinde, než kde se projeví.
- Dejte pozor nejen na vlastní kód, ale i na deklaraci podprogramu, zejména deklaraci datového typu proměnných. Chybu může působit jak nedeklarování vhodného datového typu tam, kde je deklarování potřeba, tak deklarování nadbytečné (např. pokud klíčová podmínka spočívá na IsMissing, tak deklarace datového typu jiného než Variant zapříčiní, že IsMissing bude vždy False, protože IsMissing funguje jen na Variant; blíže rozebírám jeden takovýto konkrétní problém s IsMissing pod konverzními funkcemi, konkrétně právě pod IsMissing).
- Vše hned testujte. Jinak se vám může stát, že mezi desítkami voláním složitě provázaných podprogramů zjistíte chybu, jenže až pozdě, v době, kdy už nevíte, co jste v posledních dnech měnili, a budete chybu pracně hledat. Naopak pokud vyzkoušíte funkčnost upravené verze hned, máte v čerstvé paměti, co jste změnili, a můžete to snadno vrátit zpět.
- Pozor na duplicitní názvy, například shodný název kolekce a volané funkce. Měl jsem kolekci Nahradit a v téže proceduře jsem volal funkci Nahradit(co, zaco) a divil jsem se, proč to nefunguje (což také ukazuje, že bývá výhodné deklarovat si proměnné hned v hlavičce, kde jsou pěkně pohromadě).
- Nezapomeňte v cyklech vynulovávat proměnné. Například pokud počítáte v cyklu vnořeném do jiného cyklu délku řetězce, ale zapomenete před tento vnořený cyklus dát
delka = 0
, tak se bude délka sčítat nejen pro jeden řetězec (což je účel), ale postupně pro všechny řetězce dohromady. - Myslím, že se nevyplácí hned po zjištění chyby začít horečně přepisovat kód. Lepší je si v klidu sednout, říci si nebo si i napsat, kde všude může být chyba, a pak tyto možnosti prověřit. Osvědčilo se mi dát si chvíli pauzu: když se člověk přestane bezhlavě hnát za jedním řešením, tak ho občas napadne jiné – a leckdy to správné. Zkuste si, zda vám to třeba taky nepomáhá.
- Nezapomeňte si jednotlivé verze během ladění zálohovat, nejlépe i s datem, časem a zejména informací o verzi včetně poznámek, v jaké fázi jste a co teď hodláte předělávat. Nejednou jsem makro zcela pokazil a musel jsem ho pracně dostávat do podoby, v níž fungovalo aspoň zčásti.
- Když něco funguje divně, zkuste zvážit přesunutí. Uvedu konkrétní příklad: spolehl jsem se u jedné akce na znak „#“, o kterém jsem měl za to, že má ve zpracovávaném dokumentu jedinou funkci – že značí jen začátky slovníkových hesel a nikde jinde se nevyskytuje. O vstupních datech to platilo, jenže jsem výše v kódu předělal externí procedurou české uvozovky na jejich kódy HTML: „ a “. To pochopitelně způsobilo zmatek, navíc se kvůli souhře několika činitelů špatně zjišťovalo, v čem je chyba.
- Pokud je to možné, testujte kód po částech, abyste mohli snadněji lokalizovat chybu.
- Protokol o změnách: existují makra a skripty, jež je složité naprogramovat, ale mají nakonec jednoduchou a přehlednou strukturu a snadno se v nich hledá chyba. Existují ale i takové, které jsou velmi rozsáhlé a rozvětvené, volají hodně externích podprogramů a chyba se v nich hledá špatně. U takových doporučuji si do nějakého dokumentu zaznamenávat protokol o všech provedených změnách.
- Chyba Selection.Find, nahrazení se neprovedlo: mám ověřeno, že se ve velmi výjimečných případech ve wordovském dokumentu nahrazení neprovede, ač je v kódu vše v pořádku, ale po restartu Wordu se, zřejmě za týchž podmínek (stejný kód, stejný segment textu), provede. Jako by tato funkce někdy, byť velmi zřídka, selhávala, stejně jako někdy vůbec nefungují např. automatické opravy a po restartu Wordu pracují zase výborně. Proto pokud narazíte na chybu funkce Selection.Find, o které se zdá, že nemá příčinu, než začnete přepisovat kód, zkuste zavřít aplikaci, znovu ji spustit a provést testování znovu. Ačkoli nevylučuji zcela, že mohlo jít o mou chybu.
- Speciální program na ladění VBScriptu a JScriptu: Script Debugger, volně dostupný na http://msdn.microsoft.com/scripting. Ale ke spoustě věcí stačí samotný WSH a jeho chybová hlášení, ve kterých je obsažen řádek a znak, kde k chybě došlo. Proto je dobré užívat editory, které zobrazují aktuální pozici (řádek i sloupec), například CodePad.
Chyby
- Ošetření chyb je třeba věnovat velkou pozornost.
- Příkaz, co se má dělat, když dojde k chybě: jsou dvě možnosti. Buď příkazem
On Error GoTo číslo
odeslat řízení na řádek označený na začátku příslušným číslem, nebo pomocíOn Error Resume Next
přikázat, aby byly chyby ignorovány a aby se pokračovalo ve vykonávání kódu i když dojde k chybě. Lze to kombinovat, např. dát On Error Resume Next, ale pak v nějaké chvíli zachytávání chyb zakázat a dát On Error GoTo 1. - On Error GoTo: lze prostě nějaký řádek pojmenovat (očíslovat), například mu dát číslo 1, a na začátek skriptu či makra nebo někam jinam (ale před problematické místo, ne za něj) dát On Error GoTo 1. Když dojde k chybě, je řízení předáno na příslušný řádek.
- On Error Goto 0: zakazuje zachytávání chyb: jakmile objekt Err není 0, skript se ukončí s chybovým hlášením. Lze jej kombinovat s On Error GoTo X i On Error Resume Next: v některých blocích téhož skriptu užít to a v jiných ono.
- On Error Resume Next: je-li zachycena chyba, skript pokračuje příkazem následujícím za tím, který způsobil chybu. Lze to dát hned na začátek.
- Vůbec není vhodné dávat všude On Error Resume Next, zvlášť pokud nemáme chybu ošetřenou. Ignorování chyb může vést u některých skriptů k velmi neblahým následkům. Takže je pokaždé potřeba dobře zvážit, jaký způsob zacházení s chybami zvolit v příslušném skriptu, či ještě spíše v příslušném bloku kódu.
- Řešení chyb bývá zvlášť u složitých maker vhodné soustředit v kódu pro přehlednost na jedno místo, například na začátek či konec kódu, a na něm například rozčlenit kódy předpokládaných chyb pomocí
Select Case Err.Number
a vytvoříme tak speciální blok určený k řešení chyb. Řádek, kam je vepsáno toto Select Case, lze pojmenovat (očíslovat), například 1, a na začátek skriptu umístit příkazOn Error GoTo 1
. Každý Case by měl chybu s příslušným kódem pokud možno i ošetřit. Zda je dobré vřadit i chybovou zprávu, popřípadě zda je tato chyba i dostatečným důvodem k ukončení běhu makra, to je na rozhodnutí programátora v každém jednotlivém případě. - Řádky lze pojmenovávat i jinak než čísly, např.:
SouborNelzeOtevrit: MsgBox "Soubor se nepodařilo otevřít."
. Pak stačí dát:On Error GoTo SouborNelzeOtevrit
. Je to i přehlednější. - Jestliže se vyskytla chyba, udělej to a to: existuje objekt Err, který je roven nule, pokud nedošlo k chybě, a pokud k chybě došlo, tak nese specifické číslo chyby. Lze toho využít například takto:
If Err.Number <> 0 Then
zprava = "E-mail se nepodařilo odeslat: " & Err.Description
MsgBox zprava, vbCritical
End If
Lze též zapsat zkráceněIf Err <> 0
. - Vlastnosti objektu Err: Description (popis chyby, HelpContext, HelpFile, Number (číselný kód chyby) a Source (původce chyby – program, ve kterém k chybě došlo).
- HelpContext a HelpFile slouží k odkázání na kontextovou nápovědu k dané chybě.
- Metody objektu Err: Clear (vymaže obsah objektu Err) a Raise (generuje chybu).
- Generování chyby: je možné metodou Raise objektu Err. Syntaxe:
Err.Raise kód chyby
.Err.Raise je velmi užitečné pro ladění. Díky specifickým podmínkám na vašem počítači například k nějaké chybě, kterou předpokládáte na jiných počítačích, nedochází (například máte nainstalován font, se kterým makro pracuje, ale nepředpokládáte, že bude nainstalován na všech počítačích). Proto generujete předpokládanou chybu, což vám dovolí ji vyladit přesto, že na vašem PC by k ní normálně nedošlo (a tudíž byste, nebýt Raise, nemohli sledovat její průběh). - Vyčištění objektu Err: Err.Clear. To nastaví objekt Err na 0. Dává se často na konec ošetření chyby a objekt Err se tak připravuje na to, aby se do něj zachytil kód nějaké další, nové chyby.
- Kódy chyb: chyby mají své kódy, čehož lze využít. Pracuje se s nimi například takto:
If Err.Number = 4248 Then
atd. Jak s tím pracovat: nestačí to dát za řádek, na kterém k chybě došlo, protože když k ní dojde a není nastaveno On Error Resume Next, tak se vykonávání kódu zarazí už na řádku s chybou. K odeslání na místo kódu, které řeší chybu, je nutné dát ještě někam před chybu On Error Goto X, kde X je nějaké číslo, a vytvořit, většinou na konci, pojmenovaný řádek označený číslem X na začátku. Pak to bude vypadat např. takto:
Sub PrvniZnak()
On Error GoTo 1
znak = ActiveDocument.Characters.Item(1)
MsgBox znak
Exit Sub
1 If Err.Number = 4248 Then
MsgBox "Není otevřen žádný dokument. Makro se nyní ukončí."
Exit Sub
End If
End Sub - Není ale nutné užívat číslované řádky, a v jazyce VBScript mi to ostatně ani nešlo. Ještě lepší je totiž zjišťovat, zda došlo k chybě (
If Err.Number <> 0 Then
) a pokud ano, předat řízení zvláštní proceduře, která chybu vyřeší. - Dobrá možnost, jak skript ukončit za určité podmínky: skript lze samozřejmě ukončovat i když nedošlo přímo k chybě v tom smyslu, že by se naplnil objekt Err, ale došlo k něčemu, co činí další vykonávání kódu bezpředmětným či přímo nebezpečným. Příklad:
datum = InputBox("Zadejte datum ve formátu bez mezer, např. 1.1.2003:")
If datum = "" Or Not IsDate(datum) Then
MsgBox ("Nebylo zadáno platné datum nebo je letopočet menší než 1 či vyšší než 9999. Makro se nyní ukončí.")
Exit Sub
End If - Protokolování chyb: o chybách lze vytvářet protokol, například do textového souboru, který pak si lze pak i například automaticky odeslat e-mailem. Je dobré v protokolu uvést datum a čas chyby, původce (Err.Source), případně u sítě také uživatele, kteří byli přihlášeni, když k chybě došlo, atd.
- Možnost využít externí skript: je dobré mít na paměti, že chyby mohou řešit také externí skripty či (ve VBA) zvláštní procedury či funkce daného modulu: stačí zadat třeba příkaz
On Error GoTo 1
a na řádku 1 mít třeba
Set wshshell = CreateObject("Wscript.Shell")
wshshell.run ("C:\Skripty\resenichyby5.vbs")
Pokud si mají skripty nějakou informaci předat, tak je třeba ji zapsat do pracovního souboru. Naopak procedurám a funkcím v témže skriptu či modulu ji lze předávat jako argument.
Komunikace s uživatelem: získávání informací, informační a chybová hlášení, MsgBox
Vestavěné funkce
- Stavový řádek: do stavového řádku aplikací lze ve VBA vkládat text pomocí vlastnosti StatusBar. Příklad:
StatusBar = "Probíhá nahrazování..."
. Lze tam vkládat i proměnné, takže když se něco zpracovává postupně, třeba pomocí cyklu, tak může vypadat působivě a „akčně“, když se dá do stavového řádku ta právě zpracovávaná. Na stavovém řádku lze také šikovně sdělit uživateli, co se děje, aniž by se přerušoval běh makra. StatusBar není funkční pro skripty spouštěné přes WSH, ale ověřil jsem, že tam nepůsobí chybu. - Pípnutí: příkaz Beep.
- InputBox: InputBox (okénko s textovým políčkem) je určen k zjištění informace od uživatele, která se uloží do proměnné.
- Syntaxe:
proměnná = InputBox(text zprávy[, Titulek okénka][, výchozí text][, pozice okénka na ose x][, pozice okénka na ose y][, odkaz na soubor s nápovědou, kontext])
. Text zprávy: text, který se zobrazí na okénku. Výchozí text: pokud je zadán, objeví se v textovém políčku (jako označený a přepsatelný). Pozice x a y: souřadnice vzhledem k levému hornímu rohu. - Jak získat číslo: je dobré nezapomínat, že InputBox vrací řetězec (datový typ String). Pokud chceme číslo, použijeme konverzní funkci Val:
vek = Val(InputBox("Kolik je vám let?"))
. - Jak si ověřit, zda uživatel skutečně něco zadal: pokud měl něco zadat do
cilovyadr = InputBox("Zadejte cestu k cílovému adresáři:")
, tak si nejdříve ověříme, zda vůbec něco zadal, a pokud ne, budeme na to reagovat:If cilovyadr = "" Then
atd. – následovat bude, co má skript udělat, pokud nebyl cílový adresář zadán. - Jak ověřit, zda uživatel zadal to, co měl: to je taky potřeba. Například pokud měl zadat datum, je potřeba zjistit, jestli platné datum opravdu zadal. Tam použijeme funkce ověřující hodnoty proměnných, například IsDate, IsNumeric apod. Také lze použít doprogramované funkce, které VB 6 nemá, například moje funkce IsAlpha a IsAlphaNumeric mezi makry.
- To, co uživatel zadal, může být výhodné přizpůsobit potřebám našeho makra, například to oříznout od mezer funkcí Trim či převést na samá malá písmena pomocí LCase.
- MsgBox: funkce MsgBox je určena buď k prostému zobrazení zprávy, nebo i k získání návratové hodnoty Ano, Ne, Cancel atd. Funguje ve VBS i VBA. Syntaxe:
MsgBox (zpráva, tlačítka a ikony, titulek, soubor nápovědy, kontextová nápověda)
. Možné kombinace tlačítek: vbOkOnly, vbOkCancel, vbYesNo atd.; blíže viz nápovědu pod MsgBox. - Z MsgBox je možné získávat návratovou hodnotu, a to tak, že se MsgBox přiřadí proměnné:
odpoved = MsgBox("Má se soubor odstranit?", vbYesNo + vbExclamation)
. Návratové hodnoty: viz níže. S návratovou hodnotou se dále pracuje třeba takto:If odpoved = vbYes Then
atd. - Návratové hodnoty MsgBox: OK 1, Cancel 2, Abort 3, Retry 4, Ignore 5, Yes 6, No 7.
- Možnost ignorovat hodnotu: funkce MsgBox vrací hodnotu, ale pokud ji nechceme zachytit do proměnné, můžeme ji ignorovat (běžné je to například u takového MsgBox, které může vrátit jen hodnotu vbOK).
- Jak dál pracovat s návratovou hodnotou: snadno. Například:
If odpoved = vbYes Then
atd. Lze zadávat konstanty VB nebo číselné kódy návratových hodnot. - Styl MsgBox (tlačítka a ikona): 0 OK, 1 OK Storno, 3 Ano Ne Storno, 4 Ano Ne, 16 ikona Stop, 32 ikona Otazník, 48 ikona vykřičník, 64 ikona informace. Lze zadávat buď těmito čísly, nebo konstantami VB: vbCritical (červený křížek), vbQuestion, vbInformation (informace), vbExclamation (vykřičník v žlutém trojúhelníku), vbYesNo, vbOKCancel, vbYesNoCancel aj.; viz nápovědu pod „MsgBox“. Styl lze kombinovat pomocí znaménka „plus“: vbYesNo + vbCritical.
- Příklad: Ano Ne v MsgBox: následující MsgBox bude mít styl 4, tj. Ano Ne:
odpoved = MsgBox("Mají se smazat všechny dočasné soubory?", 4)
. Místo čísla 4 lze také zadat konstantu vbYesNo. Blíže viz nápovědu pod „MsgBox“. - Výchozí tlačítko: lze nastavit, které tlačítko má být výchozí. Např.:
odpoved = MsgBox("Dokument je rozsáhlý a běh makra může trvat dlouho. Chcete přesto pokračovat?", 4 + vbDefaultButton2)
. 4 je styl vbYesNo. Konstanta vbDefaultButton2 určuje, že výchozí bude druhé tlačítko, což je v MsgBox, které má styl 4, tlačítko Ne. Nesmí se zapomínat na znak „plus“. - Parametry funkce MsgBox si lze předem vložit do proměnných (třeba msg, styl atd.) a pak napsat jen:
odpoved = MsgBox(Msg, Style, Title, Help)
. Může to kód zpřehlednit a umožní to hodnoty použít opakovaně v různých MsgBoxech – nevypisovat je znovu. - Pozor na MsgBox jako součást stránky HTML. Klasická syntaxe
MsgBox("Výpis všech hypertextových odkazů na stránce:" & vbCrLf & seznamodkazu, , "Výpis odkazů")
působí chyby. Je potřeba vynechat závorky:MsgBox "Výpis všech hypertextových odkazů na stránce:" & VbCrLf & seznamodkazu, , "Výpis odkazů"
. (testoval DZ) - Zprávy a otázky ve VBS: ve VBS se otvírá několik způsobů, jak něco uživateli sdělovat či od něj zjišťovat návratovou hodnotu (vedle výše probraného InputBox): metoda Echo objektu Wscript, metoda PopUp objektu Wscript.Shell a MsgBox.
- Co z toho použít: záleží na tom, čeho chceme docílit. Wscript.Echo je jen k vypisování; nelze s jeho pomocí získávat návratovou hodnotu; pokud se zobrazí v podobě okénka, tak v jeho záhlaví zobrazuje dlouhý řetězec „Windows Script Host“; naopak pokud se u MsgBox nastaví titulek, tak se zobrazuje v záhlaví okénka jen ten. PopUp je chytřejší než MsgBox o důležitý parametr čekání: lze jím určit, aby se PopUp automaticky zavřel, pokud není návratová hodnota uživatelem do specifikovaného počtu sekund zadána, a vrátil hodnotu -1. MsgBox a PopUp je vždy zpráva v okénku. Wscript.Echo normálně také, ale pokud byl skript spuštěn přes příkaz cscript z příkazového řádku, tak se Echo pošle do příkazového řádku, narozdíl od MsgBox, které má běžnou podobu i při spuštění skriptu přes cscript (ověřeno). Vypsání do příkazového řádku může být leckdy výhodné, jindy spíš vadí: je potřeba se rozhodnout v každém jednotlivém případě a zvolit tu variantu, která se na danou situaci hodí lépe. Pokud je potřeba získat návratovou hodnotu (např. odpověď na dotaz), tak je potřeba MsgBox nebo PopUp.
- PopUp: WSH má oproti VBA 6 navíc metodu PopUp objektu WshShell, která je v mnohém lepší než MsgBox. Umožňuje totiž zadávat čas, za který se má okno zavřít a vrátit hodnotu -1 i bez toho, aby uživatel cokoli udělal. Syntaxe:
odpoved = WshShell.Popup(zpráva, čekání, titulek, styl: tlačítka a ikony)
. Čekání: počet sekund. Po vypršení se zavře a vrátí hodnotu -1 (nikoli výchozí odpověď, jak se v některých knihách mylně uvádí: dokazuje to příklad s dotazem, zda má uživatel rád čokoládu, který je uveden níže). Nula je neomezené čekání. Jinak je Popup dost podobné MsgBox: má styly vbOkOnly, vbOkCancel, vbYesNo, vbInformation atd. Pozn.: objekt WshShell je pochopitelně třeba nejprve vytvořit:Set wshshell = CreateObject("Wscript.Shell")
. Objekt lze samozřejmě nazvat i jinak, např. ws. - Nevýhoda PopUp: pokud není užito na stránce WWW, nýbrž v běžném skriptu, je potřeba, aby měl uživatel nainstalovaný Windows Script Host, a to i tehdy, když je PopUp začleněno například do wordovského makra.
- Návratové hodnoty WshShell.PopUp: OK 1, Cancel 2, Abort 3, Retry 4, Ignore 5, Yes 6, No 7. A dále jsem u PopUp zjistil hodnotu -1, která znamená nezadáno, skript si odpověděl automaticky (nelze ale, jak se zdá, použít Empty – je nutné pracovat s číselnou hodnotou).
- Čekání: důležitý atribut. Určuje, kolik sekund se má čekat, než se PopUp zavře a vrátí hodnotu -1. Vytvořil jsem příklad, který fungování názorně osvětlí a zároveň ukáže, že se to dá použít i mimo soubor .VBS – třeba v běžném wordovském makru, ovšem za předpokladu, že uživatel má WSH; viz níže.
- Styl PopUp (tlačítka a ikona): 0 OK, 1 OK Storno, 3 Ano Ne Storno, 4 Ano Ne, 16 ikona Stop, 32 ikona Otazník, 48 ikona vykřičník, 64 ikona informace. Lze zadávat buď těmito čísly, nebo konstantami VB; blíže viz nápovědu pod „MsgBox“.
- Automaticky se zavírající zpráva či dotaz: jsou situace, kdy se chceme uživatele na něco zeptat, ale pokud neodpoví do určité doby, tak pokračovat ve vykonávání kódu. K tomu lze použít několik postupů. Jednak spustit skript, který pošle po určitém čase přes SendKeys Enter do volajícího programu; to je dost hrubý nástroj, ale někdy prakticky jediná možnost pro ovládání externích programů spouštěných skriptem. Další, velmi šikovná možnost je nepoužít MsgBox, nýbrž PopUp (viz níže), což ovšem předpokládá WSH (pokud to není použito jen na stránce WWW, kde si prohlížeč vystačí sám); to je nevýhoda, ale WSH stejně musejí mít všichni, kdo chtějí spouštět skripty ve VBS, a minimálně ve Windows XP Professional je součástí standardní instalace. A konečně lze použít API.
- VBS: tam je to snadné.
odpoved = wshshell.Popup ("Zpráva", čas ve vteřinách, titulek, ikona + tlačítka)
. Příklad:odpoved = wshshell.Popup("Máte rádi čokoládu?", 5, "Dotaz", 4 + 32)
. - VBS se dá ale využít i např. ve wordovském makru, jen je nutné, aby uživatel měl nainstalovaný WSH (ve Windows XP, minimálně v Professional, je součástí standardní instalace):
Sub AutoReply()
'Výuková ukázka na automatickou odpověď po 3 vteřinách čekání.
'Přes MsgBox to ve VB 6 nejde, tak použijeme Wscript.
Set wshshell = CreateObject("Wscript.Shell")
Odpoved = wshshell.Popup("Máte rádi čokoládu?", 3, "Dotaz", 4 + 32)
Select Case Odpoved
Case -1
MsgBox "Mlčení znamená souhlas."
Case 7
MsgBox "Vida, nemáte."
Case 6
MsgBox "Já taky."
End Select
End Sub - Pomocí API: v knížce Kocich, Pavel – Gürtler, Martin, 1001 tipů a triků pro Visual Basic, Computer Press, Praha 2000, s. 82-83 jsem pro to našel postup přes API, ale nebyl jsem schopný jej zprovoznit, ani za použití všelijakých změn a přeskupování, protože se nevyznám v práci s API. Tam uvedené řešení vypadá přibližně takto:
Sub SamozaviraciZprava()
Public Const NV_CLOSEMSGBOX As Long = &H5000&
settimer Me.hWnd, NV_CLOSEMSGBOX, 5000, AddressOf TimerProc
Odpoved = MsgBox("Opravdu chcete odstranit diakritiku z celého dokumentu?", 3 + vbDefaultButton2 + vbExclamation)
MsgBox "Tak se to zavřelo."
End Sub
Public Sub TimerProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal idevent As Long, ByVal dwtime As Long)
Dim hMsgbox As Long
killtimer hWnd, idevent
If idevent = NVCloseMsgBox Then
hMsgbox = findWindow("#32770")
If hMsgbox Then
setforegroundwindow hMsgbox
SendKeys "{enter}"
End If
End If
End Sub
K tomu ale nemohu připojit žádný komentář. Dost možná to ani není otázka VBA a VBS, nýbrž VB. - Skriptování na straně klienta ve VBS: tam se postupuje úplně stejně: MsgBox i Popup je funkční. Je ovšem třeba myslet na to, že VBScript funguje jen v IE; JavaScript zvládne IE i Mozilla a další prohlížeče a je stále standardem.
- Vyplněné údaje lze uložit do textového souboru. Pokud se váš skript ptá na hodně údajů, a přitom uživatel většinou bude vyplňovat to stejné, je dobré, když skript vytvoří textový soubor, zapíše do něj údaje, které se spíš měnit nebudou, a při každém dalším spuštění soubor načte a zeptá se uživatele, zda se mají použít údaje, které jsou v něm uložené.
- K formátování zprávy pro uživatele lze využívat tabulátor (vbTab). Dosáhne se tak shodného zarovnání. Na příklad se můžete podívat do makra DlouhoLiTomu mezi makry.
Formuláře ve VBA
- Práce s formuláři je celá věda a dají se s nimi tvořit dost rozsáhlé aplikace. Ale nezabýval jsem se jimi moc do hloubky, takže tu o nich najdete jen pár amatérských údajů. Pokud vás zajímají, zkuste načerpat znalosti v knihách. V nápovědě jsem naopak pořádný úvod nenašel.
- Ve VBScriptu tyto formuláře nejsou.
- Zobrazení formuláře: pomocí jména formuláře a metody Show: do kódu makra zapojte
UserForm1.Show
. Pokud je formulář v témže modulu, zobrazí se. - Vlastnosti formuláře: lze nastavovat. Jméno, barva, pozice atd.
- Odentrování formuláře: přidejte z ToolBox CommandButton a pak dejte pod místní nabídkou View Code. Řekněme, že chcete přiřadit tlačítku CommandButton1 funkci, která formulář zavře. V tom případě dáte:
Private Sub CommandButton1_Click()
Unload Formular
End Sub
kde Formular je název formuláře. - Text textových políček: odkazuje se na něj prostřednictvím názvu políčka a vlastnosti Text. Příklad:
TextKVyhledani = TextBox1.Text
, respektive včetně názvu formuláře:MsgBox Hledani.TextBox1.Text
. - Jak text předávat: jenže pozor, nejde prostě z procedury odkázat
MsgBox Hledani.TextBox1.Text
(aspoň pokud vím; vracelo to prázdný řetězec). Je nutné text předat z rámce formuláře. Asi to dělám zbytečně složitě, nicméně budiž, jednodušeji to neumím: prostě tlačítku OK přiřazuji volání procedury, které předávám jako parametr TextBox1.Text a případně další řetězce a hodnoty z formuláře. V této proceduře je pak obsažen celý zbytek makra. Zajímavé je, že poté, co tato procedura skončí, se běh ještě vrátí do podprogramu, ze kterého jsme si formulář zobrazili (ověřeno). Pokud tam ale už stojí jen End Sub, tak se prostě hladce skončí. Řekl bych, že existují nějaké lepší postupy, ale já je neznám. - S textovým políčkem lze spojit událost Change: v kódu formuláře se napíše:
Private Sub TextBox2_Change()
MsgBox "Právě byl napsán znak " & TextBox2.Text
End Sub - Zaškrtávací políčko (OptionButton): má hodnoty False (nezaškrtnuté) a True (zaškrtnuté). Na hodnotu se odkazuje tímto způsobem:
OptionButton1.Value
. - Jak po zavření formuláře pokračovat ve vykonávání kódu a vzít v úvahu návratovou hodnotu: stačí vepsat do kódu příslušného tlačítka CommandButton příkaz
Call pokracovani(hodnota)
, kde pokracovani je název makra, které obsahuje kód, jímž se má pokračovat, a hodnota je hodnotou, která se má předat.
Textový soubor: načítání, vytváření, zapisování atd.
- Otevření existujícího textového souboru: k tomu se užívá metoda OpenTextFile objektu FSO:
Set txt = fso.OpenTextFile("C:\pokus.txt")
. Pokud je do této metody dodána jako parametr internetová adresa (URL), dojde k chybě. Nejprve je samozřejmě potřeba mít objekt FSO:Set fso = CreateObject("Scripting.FileSystemObject"
. - Čtení souboru po řádcích: nejlepší je použít metodu ReadLine objektu zastupujícího textový soubor otevřený přes metodu OpenTextFile objektu FSO:
txt = fso.OpenTextFile("C:\pokus.txt")
.
radek = txt.ReadLine - Podmínka zastavující čtení po řádcích na konci souboru: v cyklu Do ... Loop se zadá:
Loop Until txt.AtEndOfStream
, kde txt zastupuje objekt TextStream – soubor otevřený metodou OpenTextFile. O to, aby stroj přečetl v cyklu Do ... Loop při zadání txt.ReadLine vždy následující řádek, a ne ten, který už jednou načetl, se není třeba starat: děje se tak zcela automaticky. - Přeskočení řádku: metoda SkipLine. Zapisuje se stejně jako ReadLine.
- Přeskočení specifikovaného počtu znaků: metoda Skip; do závorky se jako parametr dodá počet znaků.
- Jiná možnost čtení souboru po řádcích:
Dim retezec As String
Open "C:\soubor.txt" For Input As #1
Do While Not EOF(1)
Line Input #1, retezec
Loop
Close #1
Řádek se načítá při každém průběhu cyklu do proměnné retezec. Funguje to dobře. (Měl jsem tu dřív pěknou hloupost, takže mi tento způsob načítání nefungoval, ale jeden čtenář mi poradil, jak to má být správně; díky.) - Načítání binárních souborů: to jde taky. Postup si můžete vyzkoušet na načítání databáze v Accessu a vypisování obsahu do wordovského souboru. Vytvořte si nový dokument, uložte si pod C: novou databázi db.mdb a spusťte makro obsahující následující kód:
Open "C:\db.mdb" For Binary As #1
Do While Not EOF(1)
Line Input #1, retezec
Selection.TypeText retezec
Loop
Close #1 - Načtení obsahu celého textového souboru do proměnné: metodou ReadAll.
Set fso = CreateObject("Scripting.FileSystemObject")
Set txt = fso.OpenTextFile("C:\test.htm")
obsah = txt.ReadAll
txt.Close - S touto proměnnou lze pak pracovat jako s běžným řetězcem: užívat funkce InStr, Replace, Mid atd.; viz pod kapitolou Řetězce.
- Pokud už se užívalo na daný objekt typu TextStream metody ReadLine či SkipLine, tak ReadAll načte jen zbytek souboru, ne celý obsah (ověřeno). Toho lze samozřejmě výborně využít.
- Jiný postup načtení obsahu souboru do proměnné:
Dim txt As Integer, retezec As String
txt = FreeFile(1)
Open "C:\test.txt" For Binary As #txt
retezec = Space(FileLen("C:\test.txt"))
Get #txt, , retezec
'Nyní je obsah souboru uložen v proměnné retezec.
Close txt - Vytvoření textového souboru: pomocí metody CreateTextFile objektu FSO. Syntaxe:
Set txt = fso.CreateTextFile(název souboru, [přepsat[, unicode]])
. Přepsat: tento parametr určuje, zda má dojít k přepsání, pokud již soubor příslušného názvu v daném umístění existuje. Někde jsem četl, že výchozí je False, ale ve skutečnosti je výchozí True, jak si můžete sami vyzkoušet například na mém skriptu filelist.vbs mezi skripty. Příklad:Set txt = CreateTextFile("C:\pokus.htm")
. Samozřejmě že se může místo pevně dané cesty zadat proměnná. Pokud v daném umístění již existuje soubor téhož názvu, přepíše se bez varování novým souborem. - Lze tvořit jakýkoli textový soubor, například stránku v HTML, skript ve VBS atd.
- Zapisování do souboru: pomocí metody WriteLine objektu zastupujícího otevřený textový soubor se zapisuje řádek, tj. včetně znaku konce řádku. Pomocí metody Write se zapisuje řetězec bez znaku konce řádku. Pomocí metody WriteBlankLines se píší prázdné řádky; do závorky se dodává jako parametr počet prázdných řádků. Příklad:
Set txt = fso.CreateTextFile(filepath & "\" & filename & ".htm", True)
txt.WriteLine("<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.01 Transitional//EN"">")
U nepříliš dlouhých řetězců je asi nejlepší nejdřív si sestavit celý řetězec k zapsání a pak ho celý zapsat pomocísoubor.WriteLine retezec
. Lze takto navzdory názvu metody zapsat řádků i více, třeba celý dlouhý soubor, stačí do řetězce prostě vřetězit vbCrLf, popřípadě Chr(13) & Chr(10). - Zavření textového souboru: metoda Close.
- Dočasný soubor, volné jméno: v případě problémů s vymyšlením neduplicitního názvu pro dočasný soubor lze použít metodu GetTempName objektu FSO. Ta vrátí náhodně vybrané volné jméno souboru v adresáři dočasných souborů (s příponou TMP, na což je nutno myslet, pokud chcete použít soubor například k dynamickému vytvoření skriptu z jiného skriptu a k jeho následnému spuštění: příponu je v takovém případě nutné změnit).
- Mazání, kopírování atd.: běžnými postupy, viz kapitolu Soubory.
- Vyprázdnění: vyprázdnění textového souboru je snadné: stačí jej nově vytvořit pomocí CreateTextFile a nezapsat do něj žádná data.
- Změna pozice v souboru: příkaz Seek. V textových souborech se zadává počet znaků od začátku souboru, v binárních počet bajtů. Následující příklad zobrazí v MsgBox 18 znaků následujících po znaku s pořadovým číslem 10. Je potřeba myslet na to, že znaky konce odstavce se také počítají.
txt = FreeFile
Open "C:\test.txt" For Input As #txt
Seek #txt, 10
MsgBox Input(18, #txt) - Zjištění aktuální pozice v souboru: funkce Loc. U binárních souborů vrátí poslední čtený či zapisovaný bajt. U textových souborů vrací pozici, ale v těch se nelze pohybovat tam a zpět, takže to patrně nemá význam.[8]
Správa souborů: práce se soubory, adresáři a disky
Základní informace a postupy
- Pro velkou část práce se soubory, adresáři a disky je nutné zřízení instance objektu FSO:
Set fso = CreateObject("Scripting.FileSystemObject")
. - Metody objektu Scripting.FileSystemObject:
- BuildPath(cesta, název či fragment cesty): z cesty k mateřskému adresáři a názvu adresáře či souboru, popřípadě fragmentu cesty, sestaví cestu k této složce či souboru a u adresáře přidá, je-li to třeba, znak zpětného lomítka (pokud ale dodáte jen cestu a druhý parametr vynecháte, tak zpětné lomítko nepřidá). Příklad:
windir = fso.GetSpecialFolder(0)
cesta = fso.BuildPath(windir, "Command\skript.vbs")
To vloží do proměnné cesta v nejobvyklejším případě cestu "C:\Windows\Command\skript.vbs". - CopyFile odkud, kam[, přepsat]: zkopíruje soubor. Argument odkud specifikuje cestu ke kopírovanému souboru, argument kam specifikuje cílové umístění, a to buď jako cesta k adresáři, v kterémžto případě se soubor zkopíruje pod svým původním názvem (nesmí se zapomenout na koncové zpětné lomítko), nebo jako cesta k souboru, kde se specifikuje i název, pod kterým se má soubor zkopírovat. Argument přepsat je Boolean a specifikuje, zda má dojít k přepsání, pokud soubor příslušného názvu již existuje (výchozí hodnota overwrite je True). Příklad:
fso.CopyFile "c:\testy\test1.doc", "c:\test1-kopie.doc"
. Z příkladu vyplývá i to, že lze soubor zkopírovat pod jiným názvem. - CopyFolder: zkopíruje adresář.
- MoveFile(cesta, cílové umístění): přesune soubor či adresář.
- DeleteFile(specifikace[, mazat i ReadOnly]): ve specifikaci mohou být zástupné symboly. Pokud je parametr mazat i ReadOnly True, odstraní se i soubory s atributem Jen pro čtení.
- CreateFolder(název adresáře): vytvoří nový adresář, jehož cesta a název jsou specifikovány parametrem, a vrátí odkaz na ni. Nadřazené složky již musejí existovat. Nelze takto tedy tvořit celou cestu, nýbrž vždy jen jednu úroveň (vyzkoušeno). Lze si ale naprogramovat funkci, která v případě potřeby vytvoří celý strom.
- CreateTextFile(název, [přepsat[, unicode]]. Vytvoří textový soubor; více se dovíte v kapitole Textový soubor. Přepsat: někde jsem četl, že výchozí výchozí je True, jak si můžete sami vyzkoušet například na mém skriptu filelist.
- OpenTextFile(název): otevře textový soubor. Název obsahuje absolutní či relativní cestu.
- FileExists(specifikace): vrací True, pokud soubor existuje. Příklad:
If Not fso.FileExists("c:\autoexec.bat") Then MsgBox "Autoexec.bat neexistuje nebo není pod C:\."
- FolderExists (specifikace): analogické k FileExists.
- GetFile(specifikace): vrátí objekt File odpovídající specifikaci. Specifikace může být relativní nebo absolutní cesta.
- GetFolder(specifikace): vrátí objekt Folder odpovídající specifikaci. Specifikace může být relativní nebo absolutní cesta.
- GetDriveName (cesta): z cesty vyextrahuje písmeno disku s dvojtečkou. Pozor, leckdy je nutné použít právě tento postup. Zkoušel jsem dát prostě
pismeno = Left(ulozitkam, 1)
, což sice byl platný parametr pro fso.DriveExists, ale proSet d = fso.Drives(pismeno)
nikoli. Naopak když jsem dalSet d = fso.Drives(fso.GetDriveName(ulozitkam))
, tak tento řádek běhovou chybu nevyvolával a vše fungovalo správně. - GetAbsolutePathName (cesta): vrátí absolutní cestu k relativně zadané cestě k souboru či adresáři. Zná symboly . a .. jako odkazy na aktuální a rodičovskou složku.
- GetParentFolderName: vrátí název nadřazené složky.
- GetFileName(cesta): vrátí jméno souboru včetně přípony.
- GetBaseName(cesta): vrátí základní název souboru či složky – bez přípony.
- GetExtensionName(cesta): vrátí příponu.
- GetSpecialFolder(číslo): vrátí objekt Folder zastupující speciální složku; možné argumenty jsou 0 pro složku Windows, 1 pro systémovou složku Windows a 2 pro složku s dočasnými soubory. Jiné parametry dle nápovědy nemá. Ale také se dá využít kolekce SpecialFolders objektu Wscript.Shell, která zná více speciálních adresářů (Plocha, Start atd.). Jak se získá odkaz na speciální složku přes kolekci SpecialFolders: např.
StartMenu = wshshell.SpecialFolders("StartMenu")
. - Příklad použití metod FSO: představme si následující situaci: chceme načíst určitá data z jednoho textového souboru do jiného a tento výstup pak uložit do téhož adresáře, v jakém je zdrojový soubor, pod názvem, který je totožný s názvem zdrojového souboru, a pod stejnou příponou, ale na konec názvu chceme vložit řetězec -vystup. Cestu ke zdrojovému souboru máme v proměnné cesta. Stačí udělat toto:
CestaVystup = fso.BuildPath(fso.GetParentFolderName(cesta), fso.GetBaseName(cesta) & "-vystup." & fso.GetExtensionName(cesta))
Set vystup = fso.CreateTextFile(CestaVystup) - Metody GetFile, GetFolder a GetDrive: abychom mohli provádět mnoho užitečných operací a zjišťovat údaje nezbytné pro fungování našeho skriptu, nestačí nám často vlastní metody FSO, nýbrž potřebujeme metody a vlastnosti příslušného objektu (souboru, adresáře či disku). Proto na ně musíme získat odkaz. Postupuje se metodou GetFile, GetFolder a GetDrive objektu FSO.
Set fso = CreateObject("Scripting.FileSystemObject")
Set soubor = fso.GetFile("c:\temp\text.txt") - Vlastnosti souborů a složek: jakmile objekty Folder a File jednou máme, tak můžeme načítat a případně měnit jejich vlastnosti. Name, Path, Type, Drive, DateCreated, DateLastAccessed, DateLastModified, Size. Blíž se o tom píše níže.
- Metody souborů a složek: Copy (lze též přes metodu CopyFile objektu FSO, aniž bychom měli objekt File), Delete; v případě objektu Folder také CreateTextFile a OpenTextFile.
- Zpětné lomítko: při operacích s cestami je často potřeba, aby končily zpětným lomítkem. Dodat ho je velmi jednoduché:
If Right(cesta, 1) <> "\" Then cesta = cesta & "\"
. Také lze používat BuildPath, což je asi šikovnější.
Disky
- Ověření existence disku: metoda DriveExists objektu FSO. Název disku se zadává buď jako samotné písmeno, nebo s dvojtečkou, nebo s dvojtečkou a zpětným lomítkem. Vrací True nebo False. Zjišťuje ale jen existenci disku, ne jeho připravenost, tj. ne jestli je CD vloženo apod. Příklad:
If Not fso.DriveExists("e") Then MsgBox "Disk E neexistuje."
. - Disk existuje, i když do něj např. není vloženo CD; pomocí DriveExists se nezjistí, zda je CD vloženo.
- Získání odkazu na disk: metoda GetDrive objektu FSO. Příklad:
Set d = fso.GetDrive("c")
. Písmeno disku je možné dodat buď samotné, nebo s dvojtečkou, nebo s dvojtečkou a zpětným lomítkem. - Jak vyextrahovat z cesty písmeno disku: velmi často máme v nějaké proměnné cestu a potřebujeme z ní vyextrahovat písmeno disku, abychom je mohli dodat jako parametr do metody GetDrive. Samozřejmě je tu možnost použít
Left(cesta, 1)
. Ale asi korektnější je postup, který uvádí (ovšem bez fso, což vede ve skriptech k chybě) nápověda:pismenodisku = fso.GetDriveName(fso.GetAbsolutePathName(cesta))
. Případně pokud máte absolutní cestu, stačífso.GetDriveName(cesta)
. Vyzkoušeno. - Jakmile pomocí GetDrive získáme objekt Drive, tak můžeme využít jeho četné užitečné vlastnosti.
- Jak pracovat s vlastnostmi a metodami: nejdříve musíme získat objekt Drive metodou GetDrive objektu FSO. Např.:
Set drv = fso.GetDrive("c"): Wscript.Echo "Na disku C: je " & drv.FreeSpace & "bajtů volného místa."
- Vlastnosti objektu Drive: následují.
- FreeSpace: volné místo na daném disku v bajtech. V jedné knize se uvádí, že pokud velikost přesahuje maximální číslo, které může být Long (tj. když přesahuje 2 GB), tak vlastnost vrátí jen tuto maximální hodnotu, ne skutečnou hodnotu volného místa. Minimálně na mých XP to ale není problém – vrací přesně i vysoko nad tuto hodnotu.
- AvailableSpace: počet bajtů volného místa pro daného uživatele. Leckdy se nekryje s FreeSpace.
- DriveLetter: vrátí znak disku.
- FileSystem: vrací systém souborů na daném disku; návratové hodnoty jsou NTFS, FAT, FAT32, CDFS atd.
- DriveType: vlastnost objektu Drive. Návratové hodnoty: 0 neznámý, 1 výměnný, 2 lokální pevný, 3 síťový, 4 CD, 5 RAM. Příklad:
Set drv = fso.GetDrive("d")
If drv.DriveType = 4 Then MsgBox "Zvolený disk je CD mechanika." - IsReady: vlastnost objektu zastupujícího disk. Vrací True nebo False podle toho, zda je disk připravený. Důležité např. u CD. Příklad:
Set drv = fso.GetDrive("d")
If Not drv.IsReady Then MsgBox "Disk není připraven." - Nutnost jiného řešení ve většině případů: jenže pozor: pokud disk není přístupný, tak už řádek užívající metodu GetDrive ve výše uvedeném příkladu vyvolá běhovou chybu. Proto je potřeba ve většině případů postupovat jinak: ne přes GetDrive, nýbrž přes člen kolekce fso.Drives. Vyzkoušel jsem následující řešení a prokázalo se jako funkční:
Set fso = CreateObject("Scripting.FileSystemObject")
set d = fso.Drives("d")
If Not d.IsReady Then MsgBox "Disk D není připraven."
Tady ale zase zařízení musí existovat, jinak dochází k chybě „Zařízení není k dispozici“, takže je vhodné si jeho existenci nejdřív ověřit metodou DriveExists. - Jiné, ale zbytečně složité řešení pro případ, že by něco selhávalo: vynulování objektu Err a zadání On Error Resume Next před řádek Set drv.
- Ono vůbec platí, že odkaz na disk je často dobré (někdy i nutné) získávat přes kolekci Drives objektu FSO, nikoli přes GetDrive.
- Path: vrátí písmeno s dvojtečkou (DriveLetter vrátí jen písmeno).
- RootFolder: vrátí cestu ke kořenové složce včetně dvojtečky a lomítka.
- SerialNumber: sériové číslo disku.
- ShareName: jméno síťového disku.
- TotalSize: celková velikost.
- VolumeName: specifikuje název disku. Lze měnit.
Adresáře (složky)
- Vytvoření adresáře: adresář lze jednoduše vytvořit pomocí příkazu MkDir:
MkDir "C:\Adresar\"
. Nelze tak ale vystavět celou cestu – je třeba vždy tvořit jen do existujícího adresáře. Pokud tedy např. C:\Adresar dosud neexistuje, povedeMkDir "C:\Adresar\test1\"
k chybě. Běžnější je tvoření metodou CreateFolder objektu FSO:fso.CreateFolder "c:\novaslozka"
. Ani jeden těchto postupů neumí vytvořit strom, jen jednu složku, takže strom lze tvořit jedině postupně, po jednotlivých složkách. Lze si ale samozřejmě naprogramovat proceduru na tvoření stromu a té předávat cestu jako argument; sama by analyzovala cestu a vytvořila, co by bylo třeba. - Smazání adresáře: jednoduše pomocí RmDir:
RmDir "C:\Adresar\"
. Ale neprázdné adresáře je nutné mazat přes metodu DeleteFolder objektu FSO. - Ověření existence adresáře: fso.FolderExists. Lze zadat i relativní cestu.
- Jak se to používá:
If fso.FolderExists(nazev) Then Set fld = fso.GetFolder(nazev) Else wscript.quit
. - Pozor na chybějící s: pozor na to, aby na konci FolderExists nebylo opomenuto písmeno s.
- Získání odkazu na adresář: fso.GetFolder. Příklad:
Set adresar = fso.GetFolder(cesta)
. S tím pak dále pracujeme:soubory = adresar.Files
atd. - Kopírování adresáře: metoda CopyFolder objektu FSO se syntaxí
fso.CopyFolder zdroj, cíl, přepsat
, nebo metoda Copy objektu Folder. - Přesouvání adresáře: metoda MoveFolder objektu FSO se syntaxí
fso.MoveFolder zdroj, cíl
nebo metoda Move objektu Folder. - Mazání adresáře:
fso.DeleteFolder název, silou
nebo metoda Delete objektu Folder. - Metody objektu Folder: move (cíl), delete (silou), copy (cíl, přepsat). Přepsat je Boolean, implicitní je True.
- Vlastnosti objektu Folder: následují.
- Files: vrátí kolekci všech souborů ve složce.
- SubFolders: vrátí kolekci Folders obsahující všechny podsložky.
- Drive: vrací písmeno disku, na němž se adresář vyskytuje.
- IsRootFolder: je-li složka kořenová, vrátí True.
- Name: název adresáře bez cesty.
- Path: název adresáře včetně cesty.
- ParentFolder: vrátí objekt Folder představující rodičovskou složku.
- ShortName: název adresáře ve formátu pro DOS. Užitečné i například pro Wscript.Shell tam, kde působí spouštění chybu.
- ShortPath: vrátí absolutní cestu ve formátu osm znaků.
- Size: velikost včetně velikosti podsložek.
- Type: vrátí typ. Většinou „složka souborů“.
- Atributy:
- DateCreated: vytvoření.
- DateLastAccessed: poslední přístup.
- DateLastModified: datum poslední změny. Vrací datum a čas včetně sekund v systémovém formátu.
- Rekurze: při práci se soubory a adresáři se často hodí, když procedura volá sama sebe; například pokud pořizujeme soupis všech adresářů na disku, naprogramujeme proceduru, která vždy zjistí všechny podadresáře a pro každý z nich se sama zavolá, takže zase zjistí jejich podadresáře atd. Princip je vysvětlen v podkapitole Rekurze.
- Aktuální adresář: lze ho zjistit příkazem CurDir a změnit příkazem ChDir. Například vyzkoušeno následující:
Set fso = CreateObject("Scripting.FileSystemObject")
. Je potřeba si dát pozor na to, že pokud je aktuální jiný disk, než pro který použijeme příkaz ChDir, tak aktuálním adresářem zůstává nadále ten původní. Ke změně disku je třeba přidat ještě příkaz ChDrive "C:".
Adresar = fso.GetFolder("C:\TEMP")
MsgBox CurDir - Odkaz na aktuální složku ve VBS:
cesta = WshShell.CurrentDirectory
. - VBA – ActiveDocument.Path ve Wordu: ActiveDocument.Path vrací cestu narozdíl od GetFolder bez závěrečného lomítka. Proto:
soubor = ActiveDocument.Name
cesta = ActiveDocument.Path
jenNazev = fso.GetBaseName(cesta & "\" & soubor)
Soubory
- Ověření existence souboru:
fso.FileExists
. Vrací True, pokud soubor existuje. Podmínka určující závislost provedení akce na existenci souboru bude vypadat takto:If fso.FileExists("C:\test.doc") Then
atd. Stačí to napsat takto. Následující zápis je nadbytečný:existuje = fso.FileExists("C:\test.doc"): If existuje = True Then
atd. - Získání odkazu na soubor: fso.GetFile.
- Název souboru: vlastnost Name objektu zastupujícího soubor. Vrací jméno včetně přípony.
Set f = fso.GetFile("C:\test.doc")
jmeno = f.Name - Relativní a absolutní adresa: Lze užívat např. ..\.
- Počet souborů v adresáři: metoda Count kolekce Files. Příklad:
If adresar.Files.Count < 1 Then MsgBox ("Adresář neobsahuje žádné soubory.")
. - Kopírování souboru: syntaxe:
fso.CopyFile (zdroj, cíl, přepsat)
. Zdroj je jméno, případně včetně relativní či absolutní cesty. Lze použít zástupné znaky * a ?. Končí-li parametr cíl lomítkem, je považován za název složky a soubor se zkopíruje pod původním jménem; složka musí existovat. Nekončí-li zpětným lomítkem, pokládá se konec za název souboru: soubor se zkopíruje pod jiným názvem. - Přepsat: volitený parametr. True je implicitní hodnota. False: pokud je tak nastaveno, vyvolá chybu, pokud soubor příslušného názvu v daném umístění existuje. Soubory s atributem Read Only nelze přepsat. Lze jim ale atribut skriptem přenastavit a přepsat je potom.
- Příklad:
fso.CopyFile "c:\testy\*.txt", "c:\dokumenty\"
. Tento příklad zkopíruje všechny soubory s příponou txt v adresáři c:\testy do adresáře c:\dokumenty (pod původním názvem). - Také lze použít metodu Copy objektu File: syntaxe je
objekt.Copy cílové umístění[, přepsat]
. Objekt je vždy identifikátor objektu File. Do cílového umístění lze zadat i název souboru; v takovém případě se zkopíruje pod zadaným názvem. Přepsat: určuje, zda má dojít k přepsání, pokud již soubor daného názvu v příslušném adresáři existuje. Výchozí je True. - Kopírování všech souborů v adresáři: je tu také možnost využít příkaz CopyFiles. Příklad:
CopyFiles fso.GetFolder("c:\test"), fso.GetFolder("d:\test")
. - Zástupné znaky ve VBA: též lze užívat ? a *, ale jen u některých operací: u mazání atd. ano, ale např. u otevření přes Word ne.
- Relativní a absolutní adresa: většinou se bude zadávat absolutní. Funguje ale i ..\.
- Přesouvání: metoda MoveFile objektu FSO. Syntaxe:
fso.MoveFile zdroj, cíl
. Kopírováním lze soubor stejného názvu v cílové složce přepsat, ale přesouváním ne; pokus o přepis vyvolá běhovou chybu. - Přejmenování: přejmenovává se pomocí přesouvání do téhož umístění pod novým názvem.
- Mazání souboru: na smazání souboru existuje více postupů.
- Metoda DeleteFile objektu FileSystemObject. Syntaxe:
fso.DeleteFile název, silou
. Silou: určuje, zda se má mazat i soubor s atributem „Pouze ke čtení“ (Read Only); výchozí je False. Pozor, soubor je skutečně odstraněn, ne přesunut do koše. Lze používat zástupné znaky, např.fso.DeleteFile("c:\testy\*.tmp")
smaže všechny soubory s příponou TMP v adresáři c:\testy. - Také lze použít metodu Delete objektu zastupujícího soubor:
Set fso = CreateObject("Scripting.FileSystemObject")
Set soubor = fso.GetFile("C:\test.doc")
soubor.Delete - Jiný způsob: asi nejjednodušší je užití příkazu Kill. I u něj lze používat zástupné znaky. Příklad:
Kill "c:\temp\*.*"
. Soubory jsou mazány, ne přesouvány do koše. Příkaz Kill někdy působí chybu tam, kde fso.DeleteFile proběhne bez obtíží. Takže víc doporučuji fso.DeleteFile. - Zjištění nadřazené složky: metoda GetParentFolderName objektu FSO.
- Atributy souboru: zjišťují a mění se užitím následujících vlastností objektu zastupujícího soubor:
- DateCreated.
- DateLastAccessed.
- DateLastModified.
- Drive: písmeno disku, na kterém se soubor nachází.
- Path: název souboru s cestou.
- ShortPath: vrátí absolutní cestu ve formátu max. 8 znaků názvu a max. 3 znaky přípony (také vyřeže mezery atd.)
- Name: vrací či nastavuje název souboru.
- ShortName: název pro DOS.
- ParentFolder: vrátí objekt Folder představující rodičovskou složku.
- Size: velikost v bajtech.
- Type: vrátí typ. Txt je např. Textový dokument.
Zástupci
- Vytvoření zástupce: zástupci se tvoří metodou CreateShortcut nebo (v případě zástupce internetové stránky) CreateUrlShortcut objektu Wscript.Shell (na který nejdřív musíme získat odkaz klasickým postupem
Set wshshell = CreateObject("Wscript.Shell")
). Metoda CreateShortcut či CreateUrlShortcut vytvoří nový objekt – zástupce – a vrátí na něj odkaz. Lze tvořit zástupce adresářů, programů, dokumentů, stránek HTML atd. Parametrem CreateShortcut se zadává cesta, kde se má zástupce vytvořit (nikoli cesta k zastoupenému souboru či adresáři). Příklad:
WshShell = Wscript.CreateObject("Wscript.Shell")
Set zastupce = WshShell.CreateShortcut(cesta & ".lnk") - Cesta k zastoupenému souboru či adresáři: vlastnost TargetPath. Příklad:
zastupce.TargetPath = podadresar.Path
. Nebo:zastupce.TargetPath = "C:\Program Files\"
. - Zjištění či určení popisu zástupce: vlastnost Description objektu zastupujícího zástupce nastaví nebo vrátí popis zástupce. Příklad:
zastupce.Description = "Výroční zpráva [PDF]"
. - Úplná cesta k zastoupenému souboru: zjistí se pomocí vlastnosti FullName objektu, který obsahuje zástupce. Příklad:
Wscript.Echo "Zástupce vede k " & zastupce.FullName & "."
. - Zjištění či přiřazení klávesové zkratky: pomocí vlastnosti HotKey zástupce. Zkratka je myslím funkční jen pokud je zástupce umístěn na ploše (někde se také uvádí nabídka Start; asi ano, ale ve Windows XP možná jen nabídka Start pod All Users; nezkoušel jsem to). Syntaxe: zkratka.Hotkey = kombinace kláves (hodnoty: Alt+znak, Ctrl+znak, Shift+znak, Ext+znak; A-Z, 0-9, Tab, Clear, Escape, Space atd.). Příklad:
Set zkratka = WshShell.CreateShortcut "cosikdesi.lnk"
.
zkratka.Hotkey = "Ctrl+Alt+A" - WindowStyle: opět stejná syntaxe: zastupce.WindowStyle = hodnota. Hodnoty: 1 nastaví jako aktivní, 3 jako maximalizované, 7 jako minimalizované.
- IconLocation: určuje či zjišťuje, kde je umístěna ikona, která se pro zástupce použije. Pokud chcete použít běžné ikony, není potřeba se o IconLocation starat; ikona bude přiřazena automaticky podle typu souboru, na nějž zástupce odkazuje.
- Uložení zkratky: metoda Save:
zastupce.Save
. Užívá se poté, co je už zástupce vytvořen (je mu nastavena TargetPath atd.) – většinou na konci celého procesu jeho vytváření. - Zástupce internetové adresy: obdobné, jen je přípona .url, ne .lnk.
- Jak uložit zástupce do nabídky Start: následuje ukázka, jak se s tvorbou zástupců pracuje v praxi, na příkladu vytvoření zástupce a jeho uložení do nabídky Start. Nejdřív musíme získat cestu k nabídce Start:
StartMenu = wshshell.SpecialFolders("StartMenu")
. Pak zástupce vytvoříme:Set zastupce = wshshell.CreateShortcut(StartMenu & "\Tipy pro práci s počítačem.lnk")
. Pak nastavíme cestu k zastoupenému souboru či adresáři, případně i popis, a zástupce uložíme:
zastupce.Description = "Soubor tipů a triků pro práci s počítačem"
zastupce.TargetPath = "C:\David\PC\PC-tipy.doc"
zastupce.Save
Funkčnost jsem ověřil. Pokud chcete vytvořit celou skupinu zástupců v nabídce Start, také to zvládnete snadno: vytvoříte v adresáři Nabídka Start podadresář pomocí metody CreateFolder objektu FSO a pak do něj naskládáte své zástupce. Nezkoušel jsem to, ale mělo by to jít bez problémů. - Viz můj skript na vytvoření zástupce od všech souborů v adresáři mezi skripty, kde se ukazuje práce se zástupci v praxi a odkud lze pochytit něco, co odtud třeba není jasné.
Registr Windows
- Při úpravách registru je třeba zachovávat velkou opatrnost. Provádíte je na vlastní nebezpečí (jako všechny postupy popsané na těchto stránkách).
- Čtení: metoda RegRead objektu Wscript.Shell se syntaxí
WshShell.RegRead názevKlíče, hodnota
. - Zápis: metoda RegWrite objektu Wscript.Shell se syntaxí
WshShell.RegWrite názevKlíče, hodnota[, datový typ hodnoty]
. Pokud zapisujeme celý klíč, prostě řetězec ukončíme zpětným lomítkem. - Mazání: metoda RegDelete objektu Wscript.Shell.
- Kontextová nabídka složky v Průzkumníkovi: lze ji ovlivňovat v HKEY_CLASSES_ROOT\Directory.
Prostředí
Spolupráce makra s prostředím a různými aplikacemi
- Funkce DoEvents: přeruší na potřebný čas makro a dovolí operačnímu systému provést pozdržené akce. Dává se např. do dlouhých cyklů:
If (n Mod 1000) = 0 Then DoEvents
, popř.If (n Mod 1000) = 0 Then DoEvents()
. To znamená: pokud je n dělitelné beze zbytku 1000, proveď akce.[9] - ExpandEnvironmentString (název): vrátí obsah systémových proměnných, jejichž názvy byly zadány jako parametr. Musejí být uzavřeny mezi dva znaky %, např. %Temp%. Nic bližšího o tom nevím.
Přepínání klávesnice
- Přepínání klávesnice (VBA): nejjednodušší je spustit záznam makra ve Wordu, vybrat příslušnou klávesnici, zastavit záznam a pak nahlédnout do kódu vzniklého makra, kde se zjistí parametr, který je potřeba dodat do Application.Keybord.
- Viz makro KlávesnicePřepínač. To přepíná na základě zkratek.
- Anglická: Application.Keyboard (1033).
- Česká: Application.Keyboard (1029).
- Řecká: Application.Keyboard (1032).
- Srbská: Application.Keyboard (3098).
Programy, okna aplikace (spouštění, aktivace, ukončení, stav okna)
- Spuštění programu: program se dá spustit metodou Run objektu Wscript.Shell. Příklad:
wshshell.Run ("C:\Program Files\mozilla\mozilla.exe")
. - Aktivace okna: ve VBA prostým příkazem AppActivate titulek_okna, například
AppActivate "Microsoft Internet Explorer"
. Ve VBS je AppActivate metodou objektu Wscript.Shell:WshShell.AppActivate("Microsoft Internet Explorer")
. Pokud se parametr přesně shoduje s titulkem okna, okno se aktivuje. Pokud ne, stroj hledá, zda na to nějaké okno nezačíná; stačí tedy leckdy zadat několik prvních znaků (ale možnost chyby se tím zvětšuje). - Další možnost je využít kolekci Tasks a metodu Activate:
If Tasks.Exists("Microsoft Excel") = True Then Tasks("Microsoft Excel").Activate
. - Stav okna (maximalizace, minimalizace atd.):
- Ve Wordu:
ActiveDocument.ActiveWindow.WindowState = wdWindowStateMinimize
je na minimalizaci. Další konstanty jsou wdWindowStateMaximize a wdWindowStateNormal. - Jenže objekt ActiveDocument pochopitelně nemají všechny aplikace. Leckdy je proto dobré využít kolekce Tasks:
Tasks("Internet Explorer").WindowState = wdWindowStateMaximize
(funkčnost ověřena; dopadá to někdy výborně, někdy ne: záleží vždy na tom, jestli dřív makro doběhne k tomuto příkazu, nebo dřív IE zobrazí v záhlaví titulek stránky, který se tak stává součástí názvu položky Tasks; to by se samozřejmě dalo řešit tak, že by podmínka bylaIf Instr(uloha, "Microsoft Internet Explorer") = True Then
atd.; tak by se patrně zajistila zcela spolehlivá funkčnost). - S WindowState položek kolekce Tasks lze samozřejmě provádět lecjaké kousky: větvit to do podmínek atd.
- Velikost okna atd.: viz pod Task a Tasks v nápovědě VB různé možnosti, jak stav okna ovlivňovat.
- Maximalizace přes SendKeys: pokud nějaký postup z jakéhokoli důvodu nefunguje, zkuste „špinavé“, ale účinné řešení
SendKeys("% x")
. Někdy je potřeba nezapomenout na DoEvents. - Ukončení programu: lze provést například pomocí metody Close objektu Task. Příklad:
Tasks("Anglicko-český - Lexicon").Close
. Je potřeba znát název dané úlohy; lehce si jej lze zjistit například sestavením jejich seznamu přes makro:For Each i In Tasks: Seznam = Seznam & i & vbLf: Next: MsgBox Seznam
. (DZ) - Spuštění wordovského makra ze skriptu: jde to následovně:
Set w = Wscript.CreateObject("Word.Application")
w.visible = False
w.Application.Run("cedilla")
Něco to dělat začalo, ale často došlo k chybě; nicméně ověřeno, že se makro takto vykonalo (v našem případě to udělalo SendKeys "ç"). Stačí i jenw.Run("cedilla")
(tj. vynechat Application). Klasická syntaxe VBAw.Application.run MacroName:="cosikdesi"
nefunguje vůbec.
SendKeys: posílání sekvence kláves libovolné aplikaci
- Příkaz SendKeys ve VBA či metoda SendKeys objektu Wscript.Shell ve VBS posílá aktivní aplikaci (aktivovat ji lze přes AppActivate, respektive wshshell.AppActivate) sekvenci kláves, kterou programátor zadá do kódu skriptu. SendKeys tak umožňuje, mimo jiné, sice jen dost hrubou, ale přece jen velmi vítanou možnost automatizace i u aplikací, které nemají skriptovací možnosti, popřípadě u jejich konkrétních nabídek či funkcí, které nelze přímo ovládat ze skriptů či maker.
- Příklad ve VBA:
SendKeys "Nazdar!"
- Příklad ve VBS:
wshshell.SendKeys "Nazdar!"
. Připomínám, že aby to fungovalo, je potřeba nejdříve získat odkaz na Wscript.Shell:Set wshshell = CreateObject("Wscript.Shell")
. - Jak posílat: běžná písmena se zadávají přímo, do uvozovek. Jak se posílají speciální znaky jako Ctrl, Alt, F1 atd., to se dovíte v nápovědě VBA pod „SendKeys Statement“; obecně platí, že se dávají do svorek a že mají speciální kódy, například Delete má kód {DEL}. Nepovoluje se kombinace "^%{DEL}", která by znamenala Ctrl+Alt+Delete.
- Počet „stisknutí“: Např. 4 šipky vlevo jsou {LEFT 4}, třikrát stiskni DEL je {DEL 3}.
- SendKeys a uvozovky: pokud jsou součástí řetězce uvozovky, tak se musejí v kódu zdvojit.
- Příkazem SendKeys je možné poslat znak odpovídající nějakému kódu Chr či ChrW. Příklad:
SendKeys ChrW(8224)
, respektive ve VBSwshshell.SendKeys ChrW(8224)
. - Lze také samozřejmě poslat hodnotu proměnné.
- Klávesy, jež jsou součástí jakékoli kombinace s Shift, Ctrl, Alt: u těch písmenný kód předchází znaménko + za Shift, ^ za Ctrl a % za Alt. Takže například aby se zmáčklo Alt+F4, pošleme
SendKeys "%{F4}"
. - Další příklad (VBA): například
SendKeys ("^F")
pošle Ctrl+F. - Čekat: parametr příkazu SendKeys. Může mít hodnotu True (provádění vysílající aplikace bude pozastaveno do chvíle, než se vyslané klávesy zpracují) a False (které je výchozí), popřípadě číselná hodnota.
- U posílání kláves se někdy hodí přerušovat běh přes Wscript.Sleep.
Word a dokumenty Wordu
Úvodní informace
- Objektový model programu Microsoft Word je mimořádně rozsáhlý a lze ho skvěle využít. V možnostech automatizace, které daleko překračují možnosti jiných mně známých textových editorů, tkví jedna z největších výhod Wordu.
- Zde se z možností, které nabízí VBA při práci s Wordem, zpracovává jen zlomek. Poněkud to vyvažují makra, ze kterých je na Word zaměřena naopak velká část a která lze využít pro práci i pro inspiraci k tvorbě maker vlastních.
- Ne všechny aplikace Microsoft Office mají pokročilé možnosti skriptování. Např. FrontPage 2000 sice má okno maker, jenže jeho objektový model z nich nelze uchopit; lze tam maximálně zapsat např. nějaké operace pracující s FileSystemObject apod. Zdaleka ne všechny aplikace Office lze ovládat tak hloubkově jako Word a Excel.
- Ledacos, co uvedu níže, platí i pro Excel, popřípadě i další aplikace Office.
- Lze kombinovat VBA (wordovská makra) a VBS – spouštět skripty VBS z maker či přímo užívat VBScript v makrech (například wshshell.popup apod.). Také lze spouštět wordovské dokumenty přes VBScript a provádět operace. Obecně platí, že pokud spouštíte něco přímo z Wordu, např. makro v modulu NewMacros šablony Normal, tak nemusíte mít explicitní odkaz na Word v podobě objektu; pokud spouštíte ze skriptu, tak potřeba je. Získáte ho takto:
Set word = Wscript.CreateObject("Word.Application")
. - Makrorekordér: Word má pod Nástroje / Makra / Záznam nového makra, a též pod ZÁZN na stavovém řádku, užitečný makrorekordér, který udělá spoustu práce za vás. Neprodukuje moc čistý kód – je tam obvykle spousta nadbytečných či přímo nežádoucích informací. Proto je dobré se VBA dobře naučit, abyste kód mohli pročistit a vylepšit a samozřejmě taky použít proměnné, cykly atd. Čili: makrorekordér využijí jako užitečný nástroj čas od času i skuteční profesionálové, ale kód, který makrorekordér vyprodukuje, je dobré upravit ručně.
Otevření a zavření Wordu, Word jako objekt
- Otevření Wordu: následující příklad ukazuje, jak vytvořit instanci Wordu a otevřít nový soubor.
Set word = Wscript.CreateObject("Word.Application")
word.Visible = False
Set doc = word.Documents.Add DocumentType:=wdNewBlankDocument
Díky word.Visible = False Word nebude vidět a můžeme tam např. provádět operace, které by jinak uživatele zneklidnily. Pokud chceme, aby byl vidět, dáme True. - Ve VBA:
Set w = New Word.Application
. - Získání odkazu na Word ve VBA: oproti VBS mírně odlišná syntaxe:
Set w = GetObject(, "Word.Application")
.
Dokumenty: otvírání, ukládání, zavírání atd.
- Otevření dokumentu: pomocí
Documents.Open FileName:="C:\testy\test.htm"
. Otevření má několik užitečných parametrů. - Za jaký formát se má dokument považovat: lze dodat parametr, který určí, jak se má dokument otevřít (např. HTML lze automaticky otevřít jako TXT), což je často velmi výhodné. Format:=wdOpenFormatAuto otevře dokument jako soubor toho typu, kterému odpovídá přípona. Format:=wdOpenFormatText otevře dokument jako prostý text. Pokud „otevření jako“ nefunguje, zkontrolujte, zda je Confirm Conversions nastaveno na False:
Documents.Open ConfirmConversions:=False
. Viz též nápovědu pod „DefaultOpenFormat Property“. - Zavření dokumentu: ActiveDocument.Close. Lze přidat parametr wdDoNotSaveChanges, wdPromptToSaveChanges (výchozí) či wdSaveChanges. Příklad:
ActiveDocument.Close SaveChanges:=wdSaveChanges
. - Uložení aktivního dokumentu:
ActiveDocument.Save
. - Uložení všech otevřených dokumentů dané instance Wordu: lze užít kolekci Documents:
Documents.Save(1)
. Pokud se vynechá parametr 1, tak se Word na uložení každého dokumentu ptá (i tehdy, když je souběžně nezavírá). Parametr 1 odpovídá NoPrompt, ale to se tam nedává; dává se prostě číselná hodnota 1. - Uložit v jiném formátu:
Set w = New Word.Application
Set doc = w.Documents.Open("C:\test.doc")
doc.SaveAs "C:\test", wdFormatRTF - Uložení jako WinText 602 apod.: místo wdFormatRTF dodáme jiný parametr. Ten bychom si měli umět zjistit přes vypsání konvertorů, viz makro KonvertoryVypsatDoSouboru mezi mými makry. Jenže dochází k chybě – například argument, který má WinText 602, je údajně mimo rozsah. Vyzkoušen i o jedna nižší pro případ, že by se indexy přidělovaly od nuly, ale výsledek byl stejný.
- Jméno aktivního dokumentu včetně přípony: ActiveDocument.Name.
- Cesta k aktivnímu dokumentu: ActiveDocument.Path. Vrací cestu bez závěrečného lomítka.
- Zavření aktivního dokumentu:
ActiveDocument.Close
.
Okna wordovských dokumentů
- Kolekce Windows: ta umožňuje efektivní práci s okny. Viz nápovědu. Není ale vždy nutné pracovat s kolekcí Windows. Máme k dispozici také kolekci Documents a ta je pro ledacos vhodnější.
- Aktivace okna: pomocí AppActivate nebo
Documents.Item(i).Activate
, kde i je index.
Dialogová okna Wordu
- Využití dialogových oken Wordu ke zjištění či nastavení hodnoty: v makrech lze s velkým prospěchem využít vestavěná dialogová okna Wordu. Viz nápovědu pod „Built-in dialog box argument lists“ a „Displaying built-in Word dialog boxes“.
- Zobrazení dialogového okna Otevřít:
Dialogs(wdDialogFileOpen).Show
. - Dialog Najít: wdDialogEditFind.
- Lze přednastavit hodnoty, např.:
With Dialogs(wdDialogEditFind)
.Find = "cosi kdesi"
.Show
End With - Dialog Nahradit: wdDialogEditReplace.
Přesun po dokumentu
- Metoda GoToNext: přesune Selection na položku určenou argumentem: wdGoToComment, wdGoToPage... Příklad:
Selection.GoToNext (wdGoToPage)
. Ale není pak označený, jen dojde k přesunu. Tato metoda se umí pohybovat po následujících jednotkách: poznámka pod čarou, tabulka, objekt, strana, gramatická chyba, řádek atd., viz nápovědu pod „GoToNext Method“. Ale např. s odstavci to takto nejde. - Selection.MoveRight atd.
- Přesouvat se lze také pomocí Selection.Find.
Načítání z dokumentu do proměnných
- Načítání z dokumentu do proměnných je jedním ze základních postupů. Jakmile příslušná data v proměnné máme, můžeme s nimi pracovat za použití řetězcových operací, o kterých se píše v kapitole Řetězce.
- Jak zkopírovat vybraný text do proměnné: je to jednoduché:
promenna = Selection.text
. Pak už můžeme s proměnnou manipulovat podle chuti. - Jak vložit obsah proměnné typu String či Variant do dokumentu: pomocí
Selection.text = Retezec
(to přepíše v dané chvíli označený text, pokud nějaký označen je) neboSelection.TypeText Retezec
. Kopíruje to i se všemi složitými speciálními znaky, ale jako prostý text; nezachovává formátování. S formátovaným textem je asi nutné pracovat přes schránku. - Uchopení celého obsahu dokumentu: není nutné tak činit přes označení a Selection.text. Je tu totiž objekt ActiveDocument.Content, který zastupuje obsah dokumentu. Takže:
doc = ActiveDocument.Content
. - Jak posunout Selection a operovat se selection, s odstavci atd.: lze dát rovnítko Selection = Odstavec. Ověřeno pomocí MsgBox Selection, že ho to obsahuje. Velmi důležité, protože Selection má kolekci Words aj. Ale není to tak jednoduché, protože selection se také vkládá tam, kde je kurzor, a vlastně se tak kopíruje, čímž např. s pořadovým číslem odstavců míchá. Ale na začátku musí být něco označeného.
- Jak načíst do proměnné konkrétní slovo dokumentu: uchopíme pomocí kolekce Words objektu ActiveDocument. Například:
predchoziSlovo = ActiveDocument.Words.Item(pocetKol - 1)
. - Co vše je položka kolekce ActiveDocument.Words: na základě svého testování vím, že „slovem“ je i tečka, spojovník, enter. A jistě i další znaky. Naopak Selection.Find (a tedy ani vyhledávací dialog ve Wordu) tyto znaky za slova nepovažuje; když se v režimu zástupných znaků užije zástupný znak pro začátek a konec slova, tak je to přeskakuje. Takže do definice „slova“ užívaného metodou Find nespadají.
- Označení: u některých kolekcí lze užít metodu Select, například:
ActiveDocument.Words(1).Select
. S odstavcem to nejde. - Jak načíst do proměnné odstavec:
odstavec = ActiveDocument.Paragraphs.Item(1)
. - Jiný postup: jiná možnost je mít odstavec označený a zadat
odstavec = Selection.text MsgBox
. To je dobré tehdy, když neznáme pořadové číslo a nechceme ho zjišťovat, ale umíme se na daný odstavec přesunout. - Jak načíst do proměnné slovo odstavce: mít jej označený a zadat
Selection.Words(1)
. - Postupné uřezávání textu a zkoumání pomocí InStr: následující příklad zjišťuje počet znaků "#" v dokumentu (šlo by to řešit i šikovněji, například funkcí Split a zjištěním UBound):
maxkol = 0
ObsahujePrac = 1
ZpracovatPrac = ActiveDocument.Content
Do While ObsahujePrac <> 0
ObsahujePrac = InStr(1, ZpracovatPrac, "#")
If ObsahujePrac <> 0 Then
maxkol = maxkol + 1
ZpracovatPrac = Right(ZpracovatPrac, Len(ZpracovatPrac) - ObsahujePrac - 1)
Else
Exit Do
End If
Loop - Chceme-li pracovat s nějakou oblastí: musíme nejdřív vytvořit objekt Range, který na ni bude odkazovat.
- Selection.Extend: metoda Extend umí označovat oblasti, například v součinností se Selection.Find.
- Načtení obsahu schránky: metoda GetFromClipboard.
Schránka
- Vložení objektu do schránky: k tomu je určena metoda PutInClipboard. Příklad, kde do schránky vkládáme text:
Set d = New DataObject
d.SetText "text"
d.PutInClipboard
Selection.Paste - Získání ze schránky: metoda GetFromClipboard. Syntaxe:
řetězec = objekt.GetFromClipboard
, kde objekt je vždy DataObject. Ale nevím, jak se to používá. Takto to nejde, proměnná cb je Empty:
Set d = New DataObject
cb = d.GetFromClipboard
cb = Replace(cb, Chr(13), Chr(11))
Schránky se také týká metoda GetText, ale ani s nápovědou a s GetText jsem nevyřešil, jak získat text ze schránky do proměnné.
Psaní a úprava textu
- Jak vložit obsah proměnné do dokumentu: pomocí
Selection.text = Retezec
(to přepíše v dané chvíli označený text, pokud nějaký označen je) neboSelection.TypeText Retezec
. - Vkládání textu před a za Selection a jiné objekty: metoda InsertBefore a InsertAfter. Například:
Selection.InsertBefore "Ahoj"
. - Automatické opravy: přidání položky automatických oprav se uskuteční pomocí
AutoCorrect.Entries.Add Name:="cosikdesi", Value:="cosi kdesi"
; name je položka, value je hodnota, na kterou se má segment zaměňovat. Odstranění položky automatických oprav:AutoCorrect.Entries("cosikdesi").Delete
. Možnost vkládat položky automatických oprav přes makro mimo jiné znamená, že automatické opravy lze snadno přenést: stačí je nevypisovat do formuláře, nýbrž uvedeným způsobem do makra, a na příslušném počítači toto makru spustit. Stejně tak položky, které jsou výchozí, ale pro vás nežádoucí, je dobré zanést do makra a odstraňovat přes makro. Pozn.: automatický text se přenáší s šablonou Normal; automatické opravy ne. Proto je velmi vhodné je vkládat a odstraňovat přes makro. - Vložení textu do schránky: metoda PutInClipboard, do které se vkládá DataObject. Připomínám, že pomocí Selection.Find lze nahrazovat za obsah schránky.
Formátování textu, styly
- Viz též nápovědu pod Modifying a portion of a document.
- Fonty: FontNames je kolekce obsahující všechny nainstalované fonty. Lze ji využít například k ověření, zda je některý konkrétní font na daném PC nainstalován.
- Font: je to vlastnost, kterou lze přiřadit znaku, slovu aj. Příklad:
Set slova = ActiveDocument.Words
For Each slovo In slova
If slovo.Font.Size = 10 Then slovo.Font.Size = 12
Next
U odstavců ale Font vede k chybě. Font lze užívat u slov či u znaků, ale ne u odstavců. Odstavcům lze ale měnit styl. - Zrušení veškerého místního formátování: pomocí metody Reset, která se aplikuje různým objektům (viz nápovědu pod Reset). Například tento kód zruší veškeré místní formátování v dokumentu (ale formátování přes odstavcové styly ponechá beze změn):
ActiveDocument.Content.Font.Reset
, popřípadě
Selection.WholeStory
Selection.Font.Reset
Zruší se tak velikost písma, tučné, kurzíva, podtržené, barva atd., a také kupodivu znakové styly (což je většinou nežádoucí). Při používání pozor – jde o operaci dost destruktivní. Mezi makry také najdete makro MístníFormátováníZrušitKroměBI, které zruší místní formátování všech slov, kromě tučného písma a kurzívy (běh ale trvá ve velkých dokumentech dlouho). - Změna velikosti písma tam, kde nejde použít úprava stylů (kvůli místnímu zadání formátování): následuje příklad, který upraví každý znak v dokumentu zformátovaný velikostí 10 na velikost 12.
For Each znak In znaky
If znak.Font.Size = 10 Then znak.Font.Size = 12
Next - Výpis použitých stylů, zjištění, zda je nějaký styl použit: viz makro StylyPoužitéVypsat mezi makry. Za kód vděčím Petru Pecháčkovi. Klíčem k úspěchu je vlastnost InUse.
- Smazání nevestavěných stylů:
For Each Styl In ActiveDocument.Styles
If Styl.BuiltIn = False Then Styl.Delete
Next - Smazání stylů, které jsou sice InUse, ale ve skutečnosti použity nejsou: viz makro StylyNepoužitéVymazat.
- Přeformátování stylů podle jejich vlastností určených v šabloně: někdy je potřeba zrušit lokální hodnoty stylů a přeformátovat styly podle šablony. Určená je k tomu metoda UpdateStyles objektu Document (včetně ActiveDocument). Příklad:
For Each mydoc In Documents
mydoc.UpdateStyles
Next
Nebo pro aktivní dokument:ActiveDocument.UpdateStyles
.
Kontrola pravopisu
- Vytvoření soupisu gramatických chyb: soupis by mělo být možné velmi účinně pořídit pomocí metody GoToNext s parametrem wdGoToGrammaticalError. Ale popravdě řečeno nevím přesně jak; nebádal jsem nad tím moc dlouho. Následující kód nefungoval:
Selection.GoToNext wdGoToGrammaticalError
Soupis = Soupis & Selection.text & vbLf
MsgBox Soupis
Tabulky
- S tabulkami se dá taktéž velmi efektivně pracovat pomocí maker.
- Příklady pracující s několika objekty spojenými s tabulkami najdete např. v mých makrech ImportMillennium či TabulkaKontrolaDélkyŘádků mezi makry.
- Vložení textu do tabulky: makro TabulkaNačístText mezi makry umí následující: vložíte text dělený entery do první buňky tabulkového sloupce, označíte ho a makro ho rozloží a vloží do tabulky: vždy jeden řádek do jedné buňky.
Hledání a nahrazování: vlastnost Find (Selection.Find apod.)
- Hledání je jednou z výborně propracovaných funkcí Wordu. Neznám editor, který by umožňoval tak účinnou práci s nahrazováním jako Word, díky mnoha zástupným znakům. Víc se o zástupných znacích píše v Tipech pro práci s počítačem v kapitole věnované Wordu. Jdou s tím výborné věci.
- Nalezený text je v případě použití Selection.Find zároveň označený, je roven Selection.text. Takže když se přeruší hledání a něco se napíše a je nastaveno přepisování bloků textu, tak se přepíše nalezený řetězec. To je výhodné tam, kde nejde nahrazovat.
- Přesouvání a nepřesouvání Selection: užití Selection.Find posunuje Selection. Velmi často se ale hodí, aby se Selection neposouvala. V takovém případě použijte nikoli Selection.Find, nýbrž ActiveDocument.Content.Find (viz nápovědu pod „Finding and replacing text or formatting“, kde jsou další informace). Opakovaný zápis lze pochopitelně zkrátit tím, že si explicitně vytvoříme objekt Range:
set rng = ActiveDocument.Content
a pak jej použijeme:With rng.Find
atd. S Range se Selection nemění, ledaže bychom použili metodu Select objektu Range. - Při užití Range na nalezenou položku odkazuje objekt Parent. Příklad, kde chceme za nalezenou sekvenci – ovšem jen pokud opravdu nalezena bude – vložit text:
With ActiveDocument.Content.Find
.text = "</title>"
.Forward = True
.Execute
If .Found = True Then .Parent.InsertAfter "Toto je text vložený makrem za sekvenci </title>."
End With
Jiný příklad najdete v nápovědě pod „Find Property Example“ a „Finding and replacing text or formatting“. - Zjistil jsem, že někde ActiveDocument.Content.Find funguje problematicky. Na řádku .Execute v jednom makru pravidelně docházelo ke kousnutí Wordu (zkoušeno cca 6×). Jakmile jsem použil místo toho Selection.Find, funkčnost byla bezproblémová.
- Ověření, zda byl hledaný řetězec nalezen: Find vrací hodnotu obsahující True nebo False podle toho, zda byl řetězec nalezen.
If Selection.Find.Found = True Then
atd. Lze samozřejmě užít i v rámci bloku With:With Selection.Find ... If .Found = False Then
atd. - Hledání stylu:
Selection.Find.Style = ActiveDocument.Styles(Styl)
, nebo konkrétní zadání bez použití proměnné:Selection.Find.Style = ActiveDocument.Styles("Nadpis 1")
. Toho lze využít např. k vymazání všech nevestavěných stylů, které v dokumentu nejsou reálně použity (třebaže jsou nominálně InUse); viz StylyNepoužitéVymazat mezi makry. - Hledání písma:
Selection.Find.Font.Name = "Arial"
. - Pokud je některý parametr nějak nastaven z dřívějška, tj. z uživatelova hledání nebo nějakého jiného makra (např. MatchWildCards = True), tak pokud to při prvním nahrazování v našem makru nevrátíme na False, bude to dělat problémy. Takže v prvním použití Selection.Find je dobré raději nechat pár nadbytečností; v dalších už nejsou potřeba, protože se používá nastavení hledání, které zanechalo předchozí použití Selection.Find. Vždy, když se v jednom nahrazování či hledání nastavení mění, je pak třeba ho vrátit.
- Víckrát ReplaceAll: nestačí kupodivu k provedení. Mám spolehlivě ověřeno, že při nahrávání makra se to tak nahrává, že jen jednou je nastavení a pak vícero řádků Selection.Find.Execute Replace:=wdReplaceAll, ale to je špatně!
Toto prostě nestačí, aspoň ne za všech konstelací:
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
With Selection.Find
.text = "^p^p"
.Replacement.text = "^p"
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
Selection.Find.Execute Replace:=wdReplaceAll
Selection.Find.Execute Replace:=wdReplaceAll
Spolehlivě jsem si ověřil, že to zafunguje jen jednou. Dokonce ani
With Selection.Find
.text = "^p^p"
.Replacement.text = "^p"
.Wrap = wdFindContinue
.Execute Replace:=wdReplaceAll
End With
vůbec nestačí. Je potřeba: 1.) to rozepsat, 2.) tam dát Forward. Forward u opakovaného nahrazování není zbytečné. Toto spolehlivě ověřeno. - Makrorekordér nahrává blok Selection.Find velmi nadbytečně. Lze ho hodně zestručnit. Co lze vyřadit: v dalších použitích lze pominout všechny Match cosikdesi i Forward a Format. Ale nikdy to správně nefunguje bez Wrap, jak jsem několikrát ověřil. Pozor, nikdy není nadbytečné Wrap. Kdysi jsem se mylně domníval, že ano, ale teď jsem si opakovaně ověřil, že tomu tak není. Nadbytečné jsou i dva řádky Selection.Find.ClearFormatting Selection.Find.Replacement.ClearFormatting. ReplaceAll lze zahrnout do With. .Execute Replace:=wdReplaceAll. Takže za minimální podobu těch bloků, které následují za prvním (jenž určí celkové nastavení vyhledávání), lze považovat toto:
With Selection.Find
.text = ""
.Replacement.text = ""
.Wrap = wdFindContinue
.Execute Replace:=wdReplaceAll
End With
Krátit to víc, to obvykle nedělá dobrotu. - V posledním bloku lze případně nějaká neobvyklá nastavení (MatchWildcards = True apod.) vrátit na výchozí, aby to při dalších hledáních uživatele neobtěžovalo.
- Forward: True znamená hledat směrem zepředu dozadu, False zezadu dopředu.
- Wrap: wdFindAsk nastavuje vyvolání dialogu, zda se má v hledání či nahrazování pokračovat, jakmile se dojde na konec či začátek dokumentu či označené oblasti. wdFindContinue znamená, že se má pokračovat bez dotazu (ať už prohledává kterýmkoli směrem). wdFindStop určuje, že se hledání či nahrazování zastaví na konci či začátku dokumentu či označené oblasti.
- Jak dostat znak ^ do pole Nahradit čím: znak stříšky si Selection.Find vyhrazuje jako svůj speciální znak a nelze ho jen tak zadat do pole Nahradit čím. Jsou dvě možnosti řešení: buď použít režim zástupných znaků, kde stříšku zastupuje řetězec "^^", nebo pouze hledat pomocí Selection.Find a přepisovat znak jednom (tento druhý postup je použit v makru LingeaÚpravaZnakůAFormátuProUživatelskýSlovník mezi mými makry).
- Na nahrazování je dobré využít funkci či proceduru. Ušetří se tak spousta řádků kódu. Například lze mít v modulu NewMacros funkci:
Function Nahradit(co, zaco)
Selection.HomeKey unit:=wdStory
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
With Selection.Find
.text = co
.Replacement.text = zaco
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute Replace:=wdReplaceAll
End With
End Function
a pokaždé, když je nahrazování potřeba, ji prostě zavolat a předat jí hodnoty proměnných z volající procedury či funkce:
Call Nahradit("něco", "něco jiného")
. - Nahrazování za obsah schránky: pomocí Selection.Find lze nahrazovat za obsah schránky; zástupný znak je ^c.
- Maximální délka řetězce, který hledáme či za který chceme nahradit, je 255 znaků. Pokud potřebujete nahradit víc, zvažte rozdělení do více kroků nebo načtení obsahu dokumentu či podle možností jen příslušného místa do proměnné a užití funkce Replace (čímž se ale ztratí formátování).
- Složitá nahrazení: k nim dobře poslouží moje funkce NahrazovaciFunkce mezi makry. Pracuje ve Wordu. Nahrazuje v rámci vymezovačů Levy a Pravy všechny řetězce kryjící se s NahraditCo za řetězec NahraditZaCo; je možné zadat také podmínku, co řetězec musí nutně obsahovat a co nutně obsahovat nesmí, aby se nahrazení provedlo (Obsahuje i Neobsahuje lze předat i v podobě pole, takže lze zadat i vícero sekvencí tvořících podmínku). Lze také předat parametr určující, kolik nahrazení se má provést (výchozí je provést všechna, jež splňují daná kritéria) a také volitelný parametr pro zhotovení protokolu (soupisu všech míst v podobě, na kterou byla změněna) do nového wordovského dokumentu. Další informace o NahrazovaciFunkce najdete přímo v kódu či v informacích o makrech.
Řádky, stránky, statistika dokumentu
- Počet znaků v dokumentu: bez mezer
ActiveDocument.ComputeStatistics(wdStatisticCharacters, ZahrnoutPoznámky)
, s mezeramiActiveDocument.ComputeStatistics(wdStatisticCharactersWithSpaces, ZahrnoutPoznámky)
(za tuto informaci vděčím jednomu čtenáři). ZahrnoutPoznámky: pokud se zadá True, zahrnou se i znaky v poznámkách pod čarou a vysvětlivkách; výchozí je False. - Pro spočítání znaků včetně mezer a netisknutelných znaků lze použít taky
ActiveDocument.Characters.Count
. - Počet řádků v dokumentu: syntaxe
ActiveDocument.ComputeStatistics(wdStatisticLines)
. - Počet odstavců v dokumentu:
ActiveDocument.Paragraphs.Count
. - Počet slov a stránek: viz nápovědu pod ComputeStatistics.
- Očíslování řádků: řádky je možné ve wordovském dokumentu očíslovat následovně:
With ActiveDocument.PageSetup.LineNumbering
.Active = True
.CountBy = 1
.RestartMode = wdRestartSection
End With
Vlastnosti CountBy se přiřazuje hodnota podle toho, s jakou frekvencí mají být řádky očíslovány. Hodnota 1 znamená očíslování každého řádku, hodnota 5 každého pátého řádku atd. Číslování není vidět v normálním zobrazení.
Excel
- S Excelem skoro nepracuji a neznám jeho objektový model. Takže sem vkládám jen jakési nahodilé zlomky.
- Zobrazení hledacího dialogu:
Application.Dialogs(xlDialogFormulaFind).Show
. - Hledání v buňkách:
Cells.Find(What:="asdf", After:=ActiveCell, LookIn:=xlFormulas, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False).Activate
. - Otevření excelovského sešitu, jeho změna, uložení jako jiný sešit:
Set exc = CreateObject("Excel.Application")
set es = exc.WorkBooks.Open("cesta\soubor.xls")
es.ActiveSheet.cells(5,8)="142857"
es.SaveAs("jinacesta\jinysoubor.xls")
es.Close
Set exc = Nothing
Za tento tip vděčím jednomu čtenáři. - Práce s hodnotami v jednom sešitu a jejich uložení do jiného sešitu: ukážeme si, jak získat hodnoty tří buněk sloupce A a jak je posléze uložit oddělené středníkem do první buňky jiného sešitu.
Sheets("List1").Select
retezec = Range("A1").Value & ";" & Range("A2").Value & ";" & Range("A3").Value
Sheets("List2").Select
Range("A1").Value = retezec
Internet Explorer a skriptování na straně klienta
Různé
- Zde se o skriptování na webech mnoho nedovíte. Je tu jen několik základních informací.
- Doporučuji se u skriptování na straně klienta spíš pokud možno držet JavaScriptu, protože ho umí i Mozilla, kdežto VBScript Mozilla neovládá.
- Poznamenávám, že JavaScript a VBScript sdílejí část objektového modelu, takže vám některé uváděné informace mohou být užitečné i pro JavaScript, např. si zkuste v JS
window.alert(document.documentElement.innerHTML);
, což funguje v IE i Mozille (výjimkou je objekt document.all, který prý Mozilla nezná; neověřoval jsem). - Odkaz na externí soubor skriptu v HTML: klasicky,
<script language="VBScript" src="mujskript.vbs">
. - Jak skript na stránce HTML vypadá vypadá: pořád stejně, jak jsme zvyklí, jen musí být uzavřen do značky <script>:
<script language="VBScript">
Sub mojeFunkce_onClick
MsgBox "Klikl jsi."
End Sub
</script> - Přiřazení funkce tlačítku:
<input type="button" value="Kliknutím spustíte funkci" name="mojeFunkce">
. Takto se docílí spuštění mojeFunkce, jakmile uživatel na tlačítko klikne. Můžeme si vybrat, zda událost přiřadíme sem, nebo za podtržítko v samotné deklaraci funkce. - Načtení celého obsahu stránky do proměnné: spousty lidí jsem se ptal, jak načíst celý obsah stránky (celý její kód HTML) do proměnné a dost jsem hledal, jak se to dělá, ale bez výsledku, takže nakonec jsem na to musel přijít sám:
dokument = document.documentElement.innerHTML
. Funguje to i v Mozille, dokonce i v jejích hodně starých verzích (pochopitelně jen pokud to užijete v rámci skriptu v JavaScriptu). Načítá celý dokument, ale bez úvodní značky <html> či doctype a bez značky </html> (ověřeno). - Načtení textového obsahu stránky do proměnné (bez HTML, jen prostý text zobrazitelného obsahu):
document.documentElement.innerText
.document.documentElement.outerText
mi dává stejný výsledek; rozdíl neznám. - Načtení obsahu <body> do proměnné: snadné:
obsah = document.body.innerHTML
. Jak se načte <head>, to nevím; pokud vy ano, dejte vědět. Značky se zformátují velkými písmeny (tj. např. na <P>), i když jsou ve zdrojovém textu malými (aspoň v IE 6). - Načtení <title>:
document.title
. Připomínám, že se dokument načítá odshora dolů, takže pokud dáte skript požadující document.title výš, než se nachází samotná značka <title>, tak document.title vrátí prázdný řetězec. - Načtení uživatelského výběru:
document.selection
. Netestoval jsem. - Cesta k souboru (URL):
document.location
. - Velikost stránky v bajtech:
document.fileSize
. - Datum vytvoření stránky (souboru):
document.fileCreatedDate
. - Datum poslední změny souboru:
document.fileModifiedDate
. Vrací jen datum. - Datum poslední změny včetně času:
document.lastModified
. - Datum updatu:
document.fileUpdatedDate
. Na disku mi vrací prázdný řetězec a nevím, podle čeho se datum určuje. - Kódování:
document.defaultCharset
. Vrátí např. „windows-1250“. - Index typu kódu:
document.documentElement.sourceIndex
. Vrací index typu kódu. Nemám zjištěné všechny návratové hodnoty, ale každopádní je, že na prosté <html> vrací 0 a na<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.01 Transitional//EN"">
vrací 1. - DocType:
document.doctype
. Pokud není doctype deklarován, dojde k chybě. A pokud ano, tak taky (!). Nevím, jak se to používá. - Protokol:
document.protocol
. Např. pro protokol file vrací řetězec „File Protocol“. - Zabezpečení:
document.security
. Vrací řetězec, např. „Tento dokument nemá certifikát zabezpečení“. - document.dir: nevím, na co je.
- Odkud se uživatel na stránku dostal:
document.referrer
. Tedy snad; na disku mi vrací prázdný řetězec, i když odněkud přijdu. - Otevření dokumentu jako objektu TextStream:
dok = document.open("text/html")
. Vrací to objekt, ne text. Nevím, jak s tím pracovat. - Kontrola správného vyplnění formuláře na stránce: to VBS samozřejmě bez potíží zvládne.
- Předání hodnoty vepsané do textového políčka funkci: často máme na stránce textové políčko a potřebujeme hodnotu, kterou do něj uživatel napíše a odešle, předat funkci. Udělá se to následovně:
<form onsubmit=najit(policko.value)><input type="text" name="policko" value=""></input><input type="submit" value="Vyhledat"></input></form>
. Důležité zde je, aby: 1.) funkce byla přiřazena v elementu <form> události onsubmit, 2.) aby se příslušné textové políčko nějak jmenovalo (zde policko). Pak pomocí policko.value předáváme parametr funkci – zde funkci najit – která je deklarována např. v <head> v rámci značky <script>, třebaFunction najit(hodnota)
.
Navigace, historie
- Nejjednodušší otevření okna:
window.open("http://www.david-zbiral.cz")
. - Načíst jinou URL:
window.location.assign("http://www.david-zbiral.cz")
. - Nahradit stránku v aktivním okně stránkou jinou a tu stávající vymazat z historie:
window.location.replace("http://www.david-zbiral.cz")
.
Události
- Události: klasické, ale nepíše se to s velkými písmeny. onclick, ondblclick, onkeypress, onkeydown, onmousedown, onmouseup, onmousemove aj.
- onerror: když nastane při načítání dokumentu nebo obrázku chyba.
- onhelp: nastane, když se stiskne F1.
- onmouseover: pokud přejede nad prvkem myš.
- onmouseout: když kurzor myši opustí prvek.
- onbeforeunload: těsně před unloadem, což umožňuje například událost unload stornovat nebo se s návštěvníkem rozloučit. A taky znovu načíst příslušné okno a další nepříjemné věci, které známe z internetu.
Objektový model Internet Exploreru
- Zde rozebírám jen zlomky. Odkazuji na knihu kol., VBScript. Průvodce vývojáře, UNIS Publishing, Brno 2000, kde se dovíte daleko víc.
- Viz také nápovědu MS Script Editoru. Ale dost tam toho chybí.
Objekt Document
- images: kolekce všech obrázků na stránce.
- links: kolekce všech odkazů a bloků <area> na stránce. I relativní odkazy mají v této kolekci podobu absolutních. Příklad:
For Each odkaz in document.Links
atd. Využití: například si můžete vypsat všechny odkazy na stránce pomocí mého skriptu, který najdete mezi skripty. Pozn.: kolekce links neobsahuje prosté anchors <a> (což je dobře; ty mají vlastní kolekci anchors). - anchors: kolekce všech kotev <a>, které mají nějaké name a zároveň z nich vede nějaký odkaz (ověřil jsem, že kolekce skutečně neobsahuje všechny, které mají name, či všechny, které mají href, nýbrž jen ty, které mají oboje zároveň, takže nelze kolekci použít např. k vypsání všech záložek).
- scripts: kolekce všech segmentů uzavřených do značky <script>.
- cells: kolekce všech buněk v řádku tabulky.
- elements: kolekce všech ovládacích prvků.
- styleSheets: kolekce všech objektů StyleSheet definovaných pro daný dokument.
HTML: VBA užívaný pro přípravu stránek k publikaci (z Wordu, Excelu...)
- Kódování: lze nastavit přes wordovské makro:
ActiveDocument.WebOptions.Encoding = msoEncodingCentralEuropean
. To má výborné využití v makrech určených k přípravě wordovských souborů k publikaci na internetu, zvlášť pokud publikujete dokumenty ve více jazycích, takže potřebujete kódování operativně měnit.
Tipy, triky a řešené příklady
Odkazy na další materiály
- Doporučuji stáhnout si z těchto stránek makra; je jich hodně a jsou často podrobně komentovaná. Vyplatí se si je projít, vybrat si ta, která jsou vám užitečná, a případně si projít kód některých z nich. Také skripty jsou užitečné a leckdy podrobně komentované.
Automatické zavření dialogu po určité době
Sub AutoReply()
'Výuková ukázka na automatickou odpověď po 3 vteřinách čekání.
'Přes MsgBox to ve VBA 6 nejde, tak použijeme Wscript. DZ.
Set wshshell = CreateObject("Wscript.Shell")
Odpoved = wshshell.Popup("Máte rádi čokoládu?", 3, "Dotaz", 4 + 32)
Select Case Odpoved
Case -1
MsgBox "Mlčení po dobu tří sekund znamená souhlas."
Case 6
MsgBox "Já taky."
Case 7
MsgBox "Vida, nemáte."
End Select
End Sub
Abecední seřazení prvků pole
Následující příklad je převzat s drobnými změnami z knihy Kocich, Pavel – Gürtler, Martin, 1001 tipů a triků pro Visual Basic, s. 308-309.
Public Function AbecedníSeřazeníPole(pole, Optional l, Optional r)
'Provede abecední seřazení pole a vrátí je v seřazené podobě.
'VB ale neřadí správně podle české abecedy; "z" je pro něj menší než "ř" či "é".
'Převzato s malými změnami z knihy Kocich, Pavel - Gürtler, Martin,
'1001 tipů a triků pro Visual Basic, 308-309.
'DZ dodal optional, aby nebylo nutné l a r posílat; pokud chybí, je přiřazeno.
'Kontrola, zda jde o pole.
If Not IsArray(pole) Then
MsgBox "Nejde o pole."
Exit Function
End If
If IsMissing(l) Then l = LBound(pole)
If IsMissing(r) Then r = UBound(pole)
i = l
j = r
x = pole((l + r) / 2)
Do
Do While pole(i) < x
i = i + 1
Loop
Do While pole(j) > x
j = j - 1
Loop
If i <= j Then
tmp = pole(i)
pole(i) = pole(j)
pole(j) = tmp
i = i + 1
j = j - 1
End If
Loop Until i > j
If l < j Then Call AbecedníSeřazeníPole(pole, l, j)
If i < r Then Call AbecedníSeřazeníPole(pole, i, r)
End Function
K testování se může hodit tento kód:
Sub zk()
pole = Array("a", "x", "c", "b", "1", "2", "*")
Call AbecedníSeřazeníPole(pole)
souhrnpole = Join(pole, "")
MsgBox souhrnpole
End Sub
Následuje jiné řešení. Původní autor mi není znám. Kombinuje dva druhy řazení – podle abecedy a podle frekvence výskytu slova (vybere si uživatel v předchozím, zde neuvedeném kódu). Komentáře označené DZ jsem doplnil já. Řešení je o něco pomalejší. Ale při použití v jednom z mých maker fungovalo dobře, kdežto předchozí řešení řadilo trochu defektně (možná kvůli nějaké mé chybě).
'ABECEDNÍ SEŘAZENÍ
'DZ abecední seřazení slov. k = j. l je slovo následující. Každé slovo
'DZ porovnáváme se všemi ostatními slovy (j = 1 to WordNum - 1).
'DZ potom přeřadíme slovo na jiné místo: pokud splňuje tu složitou podmínku,
'DZ tak se posouvá jinam, výš: je rovno l, tj. posouvá se o místo nahoru (snad).
'DZ Pokud se podmínka nesplní, tak zůstává na svém místě.
For j = 1 To WordNum - 1
k = j
For l = j + 1 To WordNum
'DZ pokud (nebylo nastaveno řazení podle frekvence a následující slovo
'DZ je menší než toto slovo) nebo (se řadí podle frekvence a frekvence
'DZ následujícího slova je větší než frekvence zpracovávaného slova)
'DZ tak udělej první krok k přeřazení indexů zpracovávaného a následujícího
'DZ slova v poli Words: tímto prvním krokem je "k = l".
'DZ viz níže, jak se s tím dál pracuje. Protože cyklus probíhá se všemi
'DZ následujícími slovy (l = j + 1 To WordNum), je to úspornější
'DZ než kdyby se porovnávalo v tomto cyklu For ... Next jen s jedním
'DZ následujícím slovem. Zaráz se prostě porovná se všemi následujícími
'DZ slovy a l a j se popřehazují.
If (Not ByFreq And Words(l) < Words(k)) Or (ByFreq And Freq(l) > Freq(k)) Then k = l
Next l
'DZ pokud se podmínka splnila (a tudíž k <> j), tak dojde k posunu
'DZ v pořadí. Zpracovávané slovo j se posune o 1 výš (na místo k) a "k" se
'DZ položí jako rovné zpracovávanému slovu ("j"), tj. si prohodí index v poli
'DZ Words. Předají si také svoje frekvence, pochopitelně: frekvence se musí
'DZ přeřadit taky, jinak by neodpovídala.
If k <> j Then
tword = Words(j)
Words(j) = Words(k)
Words(k) = tword
Temp = Freq(j)
Freq(j) = Freq(k)
Freq(k) = Temp
End If
StatusBar = "Sorting: " & WordNum - j
Next j
Použití dialogového okna Procházení k výběru souboru
Cestu k souborům lze od uživatele získávat přes InputBox. Uživatelsky mnohem příjemnější je však použít klasický dialog Procházení. Zde je postup (velký dík jednomu čtenáři) – který ale nefunguje v Office 2000, zřejmě je použitelný až v novějších verzích:
Sub UseFileDialogOpen()
Dim lngCount As Long
' Open the file dialog
With Application.FileDialog(msoFileDialogOpen)
.AllowMultiSelect = True
.Show
' Display paths of each file selected
For lngCount = 1 To .SelectedItems.Count
MsgBox .SelectedItems(lngCount)
Next lngCount
End With
End Sub
Jak otevřít adresář v Průzkumníkovi
To je snadné. Stačí mít objekt Wscript.Shell a užít jeho metodu Run. Adresu lze samozřejmě zadat i v podobě proměnné.
Set ws = CreateObject("Wscript.Shell")
ws.run ("explorer.exe /n, C:\Program Files\")
Jak otevřít Internet Explorer a někam se dostat
Set ie = CreateObject("InternetExplorer.Application")
ie.navigate ("http://www.david-zbiral.cz")
ie.visible = True
Lze použít proměnnou: ie.navigate(cesta)
. Funguje to i na diskové cesty. Použití ukazuje např. můj stahovač stránek z internetu, který najdete mezi skripty. Pozorně si přečtěte komentáře skriptu; používáte jej výhradně na vlastní nebezpečí.
Jak vypisovat do okna Internet Exploreru
Nový dokument v IE (kam např. ze skriptu posíláme výpis souborů), otevřeme následovně:
Set ie = CreateObject("InternetExplorer.Application")
ie.navigate ("about:blank")
ie.visible = True
Vypisování do okna IE: navážeme např. následovně: ie.document.body.innerHTML="<p id='vystup'>"
a pak průběžně vypisovat začleněním řádku ie.document.all.vystup.insertAdjacentHTML "BeforeEnd", promenna
do funkce, která přidává nové prvky (například načítá názvy souborů a ukládá je do proměnné promenna).
Místo "beforeEnd" se může někdy hodit dát "afterBegin".
Kontrola, zda zadaná cesta existuje
Procedura, které se předá cesta a ona zkontroluje, zda tato cesta existuje. Pokud ne, vyžádá si od uživatele novou přes InputBox.
Sub kontrola(cesta)
If cesta = "" Then
wscript.echo "Cesta nebyla zadána. Skript se nyní ukončí."
wscript.quit
End If
If Not fso.FolderExists(cesta) Then
cesta = InputBox("Adresář neexistuje. Zadejte jinou cestu:")
Call kontrola(cesta)
End If
End Sub
Výpis do souboru HTML
Vytvořit dokument HTML, do kterého se např. mohou vypsat výsledky prohledávání složek na disku, pěkně přehledně a barevně, je snadné: použijí se postupy tvoření textového souboru a zapisování do něj:
Set txt = fso.CreateTextFile(fso.BuildPath(cesta, nazev & ".html", True))
txt.WriteLine("<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.01 Transitional//EN"">")
atd., pokračujeme dále podle potřeby. Samozřejmě že je možné použít pevný název a cestu; zde jsou použity proměnné.
Otevření souboru v Poznámkovém bloku
Pokud jde o soubor takové přípony, která je asociována s Poznámkovým blokem, stačí užít prostě metodu Run objektu Wscript.Shell:
Set ws = CreateObject("Wscript.Shell")
ws.run ("C:\test.txt")
Pokud tomu tak není, tak je potřeba dát:
Set ws = CreateObject("Wscript.Shell")
ws.run ("notepad C:\test.tmp")
Následující příklad otvírá právě běžící skript, v němž je tento postup zařazen, v Poznámkovém bloku:
Set ws = CreateObject("Wscript.Shell")
ws.run ("notepad " & Wscript.ScriptFullName)
Výpis do textového souboru a jeho otevření v Poznámkovém bloku
Následující příklad ukazuje, jak zobrazit uživateli výstup přes Poznámkový blok, ale zároveň soubor smazat, aby zbytečně nezůstával na disku. Uživatel si může výstup sám uložit či někam zkopírovat přes schránku. WriteLine lze samozřejmě zařadit do cyklu a výstup rozšiřovat postupně.
Set fso = CreateObject("Scripting.FileSystemObject")
tempdir = fso.GetSpecialFolder(2)
tempname = fso.GetTempName
tempfile = fso.BuildPath(tempdir, tempname)
Set txt = fso.CreateTextFile(tempfile)
txt.WriteLine "Výstup skriptu."
Set txt = Nothing
Set ws = CreateObject("Wscript.Shell")
ws.run ("notepad " & tempfile)
wscript.sleep 5000
Kill tempfile
Zkratky
API | Application Programming Interface |
FSO | FileSystemObject |
IE | Internet Explorer |
MS | Microsoft |
VB | Visual Basic |
VBA | Visual Basic for Applications |
VBS | Visual Basic – Scripting Edition (VBScript) |
WSH | Windows Script Host |
Použité zdroje
Níže uváděné zdroje pochopitelně nezodpovídají za chyby tohoto dokumentu. Velká část textu vznikla vlastním testováním.
Někde výslovně uvádím, že zdrojem jsou moje testy („testoval DZ“ a podobné poznámky). Neznamená to pochopitelně, že ostatní části dokumentu nepocházejí ode mě; je to jen poznámka, která příležitostně naznačuje, že jsem to opravdu vyzkoušel (uvádím to často mimo jiné u překvapivých výsledků).
Mezi zdroje je třeba zahrnout různá makra získaná v časopisech, na internetu aj.
Za cenné rady děkuji Petru Pecháčkovi a Miroslavu Babinskému.
Aitken, Peter G., Windows Script Host 1.0. Dávkové soubory pro Windows, Grada Publishing, Praha 2001.
Kocich, Pavel – Gürtler, Martin, 1001 tipů a triků pro Visual Basic, Computer Press, Praha 2000.
Kol., Nápověda pro Microsoft Visual Basic, in: Microsoft Office 2000.
Kol., VBScript. Průvodce vývojáře, UNIS Publishing, Brno 2000.
Kvoch, Martin – Pokorný, Jan, Programování ve Visual Basicu 5.0, Kopp, České Budějovice 1999.
PC World.
Publikování této verze: 28. 2. 2011 15:42
Sepsání: průběžně 2002-2004
Poslední celková revize: červenec 2004
Počet normostran (v přepočtu): 109
Počet slov: 29385
Umístění: http://www.david-zbiral.cz/vb.htm