Úvod do rubriky Visual Basic | Pokračujeme s VB .NET 2003 | Ján Hanák | ||||||||||||||||||||||||
|
Visual Basic :: Programátorská dílna |
|||||||||||||||||||||||||
|
Začátečník | Pokročilý | Expert | |||||||||||||||||||||||
|
![]() |
![]() |
||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||
Animace okna formuláře pomocí API funkce AnimateWindow
Okno formuláře lze při jeho vytváření nebo likvidování animovat pomocí funkce aplikačního programového rozhraní systému Windows s názvem AnimateWindow. Jelikož je API funkce AnimateWindow součástí Win32 API, je napsána v C/C++ a její prototyp vypadá následovně:
BOOL AnimateWindow( HWND hwnd, DWORD dwTime, DWORD dwFlags );
Z prototypu je zřejmé, že funkce pracuje se třemi parametry. Prvním je manipulátor okna (hwnd), tedy přesněji řečeno ukazatel na okno, které si budeme přát animovat. Ačkoliv Visual Basic .NET 2003 nenabízí programovou podporu pro práci s ukazateli, můžeme si pomoci vlastností formuláře Handle, která vrací instanci struktury IntPtr, což je ve skutečnosti přestrojený ukazatel na jistý zdroj, v našem případě okno formuláře. Druhý parametr má název dwTime a je typu DWORD. Typ DWORD je speciálním typem operačního systému, který představuje 32bitové číslo bez znaménka. Poněvadž ve Visual Basicu .NET 2003 není vestavěný datový typ s odpovídajícím rozsahem, použijeme místo typu DWORD typ Integer. Parametr dwTime determinuje časový interval realizace animace v milisekundách. Doporučovanou hodnotou pro délku animace je 200 ms. Posledním parametrem je dwFlags, opět typu DWORD. Tento parametr je připraven na úschovu konfiguračních nastavení, která říkají, jaký typ animace se má použít. V našem případě použijeme konstantu AW_BLEND, která zabezpečí zobrazení okna formuláře prostřednictvím tzv. efektu zeslábnutí (fade efekt). Jelikož hodnota konstanty je v hexadecimálním tvaru 0x00080000 (524288 v desítkové soustavě), můžeme typ DWORD ve Visual Basicu .NET 2003 nahradit typem Integer.
Kromě toho, že budeme okno formuláře animovat při jeho zobrazování, ukážeme si také, jak jej animovat při uzavírání. Za tímto účelem použijeme ještě jednu konstantu s názvem AW_HIDE, kterou pomocí logického operátoru Or zkombinujeme s konstantou AW_BLEND při uzavírání formuláře. Pro konstantu AW_HIDE platí stejná pravidla jako pro konstantu AW_BLEND: typ konstanty bude Integer a její hodnota v hexadecimálním podání je 0x00010000, tedy 65536 desítkově.
Když API funkce AnimateWindow ukončí svou činnost, vrací návratovou hodnotu v podobě datového typu BOOL, jenž můžeme v prostředí Visual Basicu .NET 2003 vhodně nahradit typem Boolean. V případě, že funkce svůj úkol splnila úspěšně, bude vrácena nenulová hodnota, která bude konvertována na hodnotu True typu Boolean. Jinak bude návratovou hodnotu tvořit hodnota False, která bude indikovat, že volání funkce nebylo úspěšné.
Spolupráci řízené aplikace Visual Basicu .NET 2003 a nativní Win32 API funkce má na starosti softwarová služba P/Invoke. Ačkoliv se nebudeme popisem stylu práce této služby nyní zabývat, vzpomeneme alespoň dva způsoby použití API funkce v řízené aplikaci. První alternativou je aplikace příkazu Declare, jehož pomocí provedeme deklaraci funkce (ve skutečnosti vytváříme řízený prototyp nativní funkce ve Visual Basicu .NET 2003). Přestože je použití příkazu Declare velice „programátorsky přívětivé“, neposkytuje nám možnost pečlivějšího nastavení způsobu komunikace mezi řízeným a nativním kódem. Budete-li chtít získat o něco větší kontrolu nad tímto procesem, můžete použít atribut DllImport z jmenného prostoru System.Runtime.InteropServices. My si však pro tentokrát vystačíme s příkazem Declare, jenž bude mít následující podobu:
Declare Auto Function AnimateWindow Lib "user32" _ (ByVal hwnd As IntPtr, ByVal dwTime As Integer, _ ByVal dwFlags As Integer) As Boolean
Dále deklarujeme konstanty AW_BLEND a AW_HIDE:
Private Const AW_BLEND As Integer = 524288 Private Const AW_HIDE As Integer = 65536
Na formulář přidejte jednu instanci ovládacího prvku Button a do jejího zpracovatele události Click umístěte kód pro vytvoření nové instance třídy Form a následné volání API funkce AnimateWindow s konstantou AW_BLEND.
Dim frm As New Form Dim btnZavřít As New Button With btnZavřít .Text = "Zavřít formulář" .Width = Len(.Text) + 50 .Height = 70 .Location = New Point(20, 30) End With frm.Controls.Add(btnZavřít) AddHandler btnZavřít.Click, AddressOf btnZavřít_Click AnimateWindow(frm.Handle, 200, AW_BLEND) frm.Show() : frm.Activate()
Poté vložte do těla třídy Form1 programový kód metody btnZavřít, která bude aktivována ve chvíli, kdy klepnete na tlačítko na nově vytvořeném formuláři.
Private Sub btnZavřít_Click(ByVal sender As Object, ByVal e As EventArgs) AnimateWindow(Form.ActiveForm.Handle, 200, AW_HIDE Or AW_BLEND) Form.ActiveForm.Close() End Sub
Když spustíte aplikaci a klepnete na tlačítko, bude vytvořen nový formulář, který bude animován. Jakmile se formulář zobrazí v plné kráse, můžete klepnout na tlačítko s popiskem „Zavřít formulář“, čímž se spustí animace uzavírání formuláře a formulář se uzavře.
Inicializace a třídění vektorového pole
Pole jsou ve Visual Basicu .NET 2003 skutečně propracovaná a je s nimi radost pracovat. Na následujících řádcích si ukážeme několik variant inicializace vektorového, tedy jednorozměrného pole, a poté uvidíte, jak lze obsah pole jednoduše setřídit pomocí sdílené metody Sort třídy Array z jmenného prostoru System.
Programovací jazyk Visual Basic .NET 2003 vám nabízí mnoho způsobů, jak inicializovat vektorové pole. Ještě předtím, než se pustíme do podrobností, si připomeňme, že pole se ve Visual Basicu .NET deklarují jinak, než je tomu v jiných programovacích jazycích platformy .NET Framework (kupříkladu v řízeném C++). Abychom si situaci usnadnili, nebudeme nyní uvažovat o dynamických polích, které lze bez potíží vytvářet až v jistém okamžiku životního cyklu .NET aplikace. Místo toho se zaměříme na pole statická, tedy pole, jejichž velikost je známá již v době kompilace zdrojového kódu programu. Při deklaraci statického vektorového pole se v jazyce Visual Basic .NET 2003 udává hodnota nejvyššího indexu pole (tedy ne hodnota počtu prvků pole, jako je tomu třeba v již zmiňovaném řízeném C++). Budete-li chtít deklarovat pole o 10 prvcích typu Integer, použijete nejspíš tento kousek kódu:
Dim VektPole(9) As Integer
Deklarační příkaz vytváří jednorozměrné pole, které obsahuje 10 prvků, jejichž indexy se počítají od nuly do devítky. Visual Basic .NET 2003 prvky pole zcela automaticky inicializuje na výchozí hodnoty použitého datového typu, tedy na nuly v našem případě. To znamená, že po vykonání deklaračního příkazu je vytvořeno nové pole, které bude mít tuto podobu:
Naše pole můžeme explicitně inicializovat pomocí různorodých technik, přičemž níže jsou uvedeny některé z nich. Programové fragmenty kódu předpokládají, že na formuláři se nachází jedna instance ovládacího prvku ListBox, která je využívána pro zobrazení hodnot prvků pole po jeho inicializaci.
Explicitní inicializace vektorového pole: 1. způsob
Dim VektPole(9) As Integer Dim x As Byte For x = 0 To 9 VektPole(x) = 2 * x ListBox1.Items.Add("Prvek č. " & x & ": " & VektPole(x)) Next
Pro tuto variantu explicitní inicializace je typická přímá determinace dolní i horní hranice pole. Jelikož pole jsou ve Visual Basicu .NET 2003 indexována od nuly, dolní hranice pole je vždy nulová. Horní hranice je v našem případě rovna devíti, je tedy o jedničku menší než hodnota udávající počet prvků pole. Je jistě snadné určit horní hranici pole u jednoduchých polí jako je to naše. Avšak při programování složitějších aplikací již toto určení tak snadné být nemusí. Abyste předešli možnosti potenciálního omylu, horní hranici pole neurčujte přímo, ale raději si pomozte spřízněnou instanční metodou GetUpperBound.
Explicitní inicializace vektorového pole: 2. způsob
Dim VektPole(9) As Integer For x As Byte = 0 To 9 VektPole(x) = 2 * x ListBox1.Items.Add("Prvek č. " & x & ": " & VektPole(x)) Next
Druhá ukázka je takřka shodná s tou první až na jednu velice důležitou odlišnost. Touto odlišností je přímá deklarace řídící proměnné x typu Byte v cyklu For...Next. Jedním dechem však musím dodat, že deklarace řídící proměnné uvnitř cyklu je dovolena pouze ve Visual Basicu .NET 2003. Pokud tedy pracujete s Visual Basicem .NET 2002, nebudeme moci tuto techniku použít. Když už jsme u těch novinek Visual Basicu .NET 2003, je třeba říct, že kromě explicitní deklarace řídících proměnných v cyklech lze v této verzi pracovat i s operátory bitového posunu.
Explicitní inicializace vektorového pole: 3. způsob
Dim VektPole(9) As Integer For x As Byte = 0 To CByte(VektPole.GetUpperBound(0)) VektPole(x) = 2 * x ListBox1.Items.Add("Prvek č. " & x & ": " & VektPole(x)) Next
Tato alternativa inicializace pole používá pro určení horní hranice pole instanční metodu GetUpperBound. Metoda přijímá jeden argument, jímž je dimenze pole, horní hranici kterého chceme zjistit. Dimenze jsou indexovány od nuly, a tudíž pro jednorozměrné pole je aplikovatelná právě nulová hodnota.
Explicitní inicializace vektorového pole: 4. způsob
Dim VektPole() As Integer = _ {0, 2, 4, 6, 8, 10, 12, 14, 16, 18} Dim x As Byte VypsatData: ListBox1.Items.Add("Prvek č. " & x & ": " & VektPole(x)) If x < 9 Then x += CByte(1) GoTo VypsatData End If
Poslední programová ukázka nepoužívá pro inicializaci pole cyklus, nýbrž přímou inicializaci při deklaraci pole. V tomto případě v deklaračním příkaze nezadáváme hodnotu horní hranice pole v kulatých závorkách, ale závorky ponecháváme prázdné. Za určením datového typu prvků pole (zde Integer) následuje operátor pro přiřazení (=), za kterým stojí dvojice složených závorek, v nichž jsou specifikovány inicializační hodnoty pro jednotlivé prvky pole. Visual Basic .NET 2003 sám rozezná, kolik prvků pole tvoří a podle toho vytvoří pole o příslušné velikosti. Zajímavostí je, že hodnoty prvků pole nezjišťujeme pomocí cyklu For...Next, ale prostřednictvím příkazu GoTo a rozhodovací konstrukce If...Then.
Na závěr si ukážeme, jak třídit prvky pole podle abecedy. Uvažujme tento fragment zdrojového kódu:
Dim VektPole() As String = _ {"Pentium", "Celeron", "486", "AthlonXP", _ "Duron", "Opteron"} Array.Sort(VektPole) For x As Byte = 0 To CByte(VektPole.GetUpperBound(0)) ListBox1.Items.Add("Prvek č. " & x & ": " & VektPole(x)) Next
Pole VektPole obsahuje šest textových řetězců, které označují názvy mikroprocesorů různých hardwarových společností. Jelikož je pole explicitně inicializované ihned při své deklaraci, textové řetězce budou do pole ukládány v takém pořadí, v jakém jsou specifikovány. Po svém vytvoření bude mít pole tuto podobu:
Když však zavoláme sdílenou metodu Sort třídy Array a předáme ji jméno pole, které potřebujeme setřídit, obsah pole se změní a bude mít tuto podobu:
Metoda Sort zabezpečí rychlé a účinné setřídění pole podle abecedy.
Umísťování více příkazů do jednoho řádku kódu
Programovací jazyky, jako je třeba C, C++ a C#, mají tu výhodu, že umožňují vývojářům zapisovat více programových příkazů na jeden řádek kódu. Trik spočívá v tom, že v těchto jazycích není konec řádku indikován symbolem znaku nového řádku, jak je tomu ve Visual Basicu, ale středníkem (;). Céčkaři tak mohou poměrně snadno uložit na jeden řádek i více příkazů, čímž mohou psát nejenom kompaktnější, ale i lépe čitelný programový kód. Ve skutečnosti jenom velmi málo programátorů ve Visual Basicu ví, že i v tomto prostředí lze na jeden řádek umístit více příkazů. Klíčem k úspěchu je použití symbolu dvojtečky (:), za kterým následuje další příkaz. Tak například níže uvedený kód, jenž se rozprostírá na třech řádcích...
Dim a As Short a += CShort(1) MessageBox.Show(a.ToString)
...můžeme pomocí ekonomičtějšího zápisu umístit na jeden řádek:
Dim a As Short : a += CShort(1) : MessageBox.Show(a.ToString)
Jednoduše za každý příkaz vložíme symbol dvojtečky a zapíšeme další příkaz. Je to skvělé, nemyslíte?
|