Integrované prostředí rubriky Visual Basic

Autor: Ján Hanák

Programátorská laboratoř

Prostor pro experimentování

Časová náročnost

(min):

70

Začátečník

Pokročilý

Profesionál

Použitý operační systém : Hlavní vývojový nástroj :

Další vývojový software :

Jiný software :

Windows 2000 SP3

Visual Basic .NET 2002

Žádný

Žádný

 

 

 

Použití sdílených datových členů, vlastností a metod

Vytváření miniatur obrázků (thumbnails)

Deklarování a generování událostí

 

 

Použití sdílených datových členů, vlastností a metod

 

Zájemci o studium objektově orientovaného programování ve Visual Basicu .NET často narážejí na potíže ve chvíli, kdy se jich zeptáte, jaký je rozdíl mezi instančními datovými členy, vlastnostmi a metodami a jejich sdílenými protějšky. Zkušenější jedinci sice dokáží vysvětlit význam a použití instančních datových položek na přijatelné úrovni, ovšem oříškem takřka vždycky bývá charakteristika sdílených datových členů. Abychom si udělali v nastíněné situaci pořádek, zaměříme se na popis jak instančních datových položek, tak i jejich sdílených kolegů.

 

Jistě víte, že když použijete správnou syntaxi příkazu s klíčovým slovem New a názvem třídy, vytvoříte instanci dané třídy. Tato nově vytvořená instance je uložena do generace 0 řízené hromady počítače.

 

Řízená hromada je oblast počítačové paměti, do které jsou ukládány takzvané řízené instance tříd. Řízená hromada je kontrolována prostřednictvím společného běhového prostředí (Common Language Runtime, CLR). CLR za účelem kontroly a správy řízené hromady využívá služeb automatické správy paměti s názvem Garbage Collection. Ačkoliv nebudeme zacházet příliš do hloubky, měli byste vědět, že instance, neboli objekty, jsou řazeny do tří generací (generace 0, 1 a 2). Nejmladší, resp. posledně vytvořené objekty, jsou vždy umísťovány do nulté generace. 

 

Většina instancí obsahuje svá vlastní data, která jsou uložena v privátních datových členech každé instance. Instance se svými daty pracují pomocí programovacích konstrukcí, mezi něž patří vlastnosti a metody. Každá vytvořená instance obsahuje svou vlastní kopii všech implementovaných datových členů, což znamená, že pro každou instanci a její datové položky je v paměti vytvořen separátní prostor, ve kterém jsou uložena citlivá data dané instance. Tímto způsobem mohou různé instance existovat a pracovat nezávisle na sobě. Datové členy, které patří instanci, se nazývají instanční datové členy. Analogicky, programovací konstrukce, které přistupují k instančním datovým členům, tedy vlastnosti a metody, jsou známé jako instanční vlastnosti a metody. Pro instanční datové členy, vlastnosti a metody je charakteristický jejich vztah k dané instanci. Jednoduše, instanční metody mohou provádět operace jenom nad daty konkrétní instance.

 

Na druhé straně existují sdílené datové členy a také sdílené vlastnosti a metody.

 

V některých programovacích jazycích, třeba v C# a v řízeném C++, jsou datové členy tohoto typu označovány jako statické. Pokud tedy někdy uslyšíte své kolegy pracující v C# mluvit o statických metodách, budete vědět, že jejich diskuse se točí kolem sdílených metod.

 

Sdílené datové členy se vztahují na třídu, spíše než na jednotlivé instance třídy. Sdílené datové členy jsou ve Visual Basicu .NET deklarovány pomocí klíčového slova Shared. Pro všechny sdílené datové členy je na řízené hromadě vytvořen souvislý prostor bajtů, v němž jsou tyto sdílené datové členy uloženy. Aby bylo možné k sdíleným datovým členům přistupovat, musejí existovat také sdílené vlastnosti a metody. Tyto entity operují se sdílenými členy, tedy daty třídy.

  

Je důležité pochopit, že sdílené vlastnosti a metody mohou pracovat jenom se sdílenými datovými členy třídy, nikoliv s datovými členy instancí dané třídy.

  

Abyste lépe pochopili rozdíl mezi instančními datovými členy a sdílenými datovými členy, prostudujte si níže uvedené obrázky.

 

 

Obr. 1 – Grafická ilustrace dvou objektů a jejich datových členů

 

 

Obr. 2 – Grafická ilustrace třídy a sdílených datových členů

 

Na následujících řádcích si předvedeme dvě programové ukázky, v nichž uvidíte použití sdílených datových členů, vlastností a metod.

 

Ukázka č. 1 – Zjištění počtu alokovaných objektů pomocí sdílených členů

V první ukázce uvidíte, jak nám mohou sdílené členy pomoci při zjišťování aktuálního stavu vytvořených objektů. Postupujte následovně:

 

  1. Spusťte Visual Basic .NET a vytvořte standardní aplikaci pro Windows (Windows Application).
  2. Přidejte do projektu soubor s kódem třídy (Projectà Add Class).
  3. Implicitně vytvořený programový kód třídy upravte podle uvedeného vzoru:

 

Public Class TřídaA

    Private Shared PočetObjektů As Integer

 

    Sub New()

        PočetObjektů += 1

    End Sub

 

    Protected Overrides Sub Finalize()

        PočetObjektů -= 1

    End Sub

 

    Public Shared ReadOnly Property ZjistitPočetObjektů() As Integer

        Get

            Return PočetObjektů

        End Get

    End Property

End Class

 

Jedná se o třídu s názvem TřídaA. V těle třídy se nachází jeden sdílený datový člen typu Integer s názvem PočetObjektů. Všimněte si, že před názvem datového členů je umístěno klíčové slovo Shared. Tím je výslovně naznačeno, že pracujeme se sdíleným datovým členem, jenž se vztahuje ke třídě jako celku.

 

Sdílený datový člen PočetObjektů je deklarován rovněž použitím klíčového slova Private. Jde tedy o soukromý sdílený datový člen, což je vhodné, protože takto dodržujeme princip skrývání dat. Princip skrývání dat představuje jeden ze základních pilířů koncepce OOP. Jednoduše řečeno, význam tohoto principu spočívá v tom, že nikdy neposkytneme klientskému kódu přímý přístup k datovému členu třídy. Místo toho hodnotu příslušného datového členu zjistíme pomocí implementované veřejné sdílené vlastnosti.   

 

Filozofie ukázky je zcela přímočará: Vždy, když dojde k vytvoření instance třídy TřídaA, bude v konstruktoru třídy inkrementován sdílený datový člen PočetObjektů. Datový člen PočetObjektů je implicitně inicializován na nulovou hodnotu. Po vytvoření každé instance bude hodnota sdíleného členu PočetObjektů zvýšena o jednotku. Před likvidací instance je proveden kód, jenž je umístěn v chráněné a překryté Sub proceduře s názvem Finalize. Jelikož je daná instance určena k likvidaci, je nutné v proceduře Finalize dekrementovat hodnotu sdíleného datového členu PočetObjektů. Aktuální hodnotu sdíleného datového členu PočetObjektů nám na požádání nabídne sdílená vlastnost ZjistitPočetObjektů. Návratová hodnota sdílené vlastnosti je typu Integer a odpovídá skutečnému počtu instancí dané třídy, které se ještě nacházejí na řízené hromadě.   

 

  1. Na formulář přidejte jednu instanci ovládacího prvku Button a také jednu instanci komponenty Timer.
  2. Ujistěte se, že vlastnost Enabled instance komponenty Timer je nastavena na hodnotu False a že vlastnost Interval této instance obsahuje hodnotu 100 (milisekund).
  3. Zpracovatele události Click instance ovládacího prvku Button upravte následovně:

 

    Private Sub Button1_Click(ByVal sender As System.Object, _

    ByVal e As System.EventArgs) Handles Button1.Click

        Timer1.Enabled = True

        Dim i As Integer

        Dim Objekt As Object

        For i = 1 To 1000

            Objekt = New TřídaA()

        Next

    End Sub

 

Tento kód vytvoří 1000 instancí třídy TřídaA.

 

  1. Obsluhu události Tick instance komponenty Timer vyplňte tímto kódem:

 

    Private Sub Timer1_Tick(ByVal sender As System.Object, _

    ByVal e As System.EventArgs)

        Me.Text = "Počet objektů: " & TřídaA.ZjistitPočetObjektů

    End Sub

 

Spusťte testovací aplikaci a klepněte na tlačítko. V titulkovém pruhu dialogového okna se objeví zpráva o vytvoření 1000 objektů. Jak jsme si již řekli, všechny objekty jsou uloženy do generace 0 řízené hromady. Objekty však po svém vytvoření nejsou nijak využívány, a proto se za krátkou dobu stanou soustem pro automatickou správu paměti. Aktuální počet alokovaných objektů se zobrazuje v titulkovém pruhu dialogu přibližně každých 100 milisekund. Jelikož je generace 0 řízené hromady vyhrazena pro dočasné objekty, za krátkou dobu budou všechny vytvořené instance z paměti odstraněny (titulek dialogového okna bude ukazovat nulovou hodnotu).

 

Ukázka č. 2 – Použití sdílené funkce třídy pro přidání instance třídy Button na aktivní formulář

Zajisté jste se již někdy střetli s třídou, která přímo neumožňovala tvorbu svých instancí. U takovéto třídy tedy není možné použít známou syntaxi s klauzulí New. Ačkoliv třída neposkytuje možnost přímého vytváření instancí, přesto může být užitečná. Ano, klíčem k úspěchu je zařazení sdílené funkce (resp. metody). Vložte do stávajícího projektu Visual Basicu .NET další třídu a její podobu upravte takto:

 

Public Class TřídaB

    Public Shared Function PřidatTlačítko _

    (ByVal Jméno As String, ByVal Návěstí As String, _

    ByVal Šířka As Integer, ByVal Výška As Integer, _

    ByVal Pozice As Point) As Boolean

        Try

            Dim Tlačítko As New Button()

            With Tlačítko

                .Name = Jméno

                .Text = Návěstí

                .Width = Šířka

                .Height = Výška

                .Location = Pozice

            End With

            Form.ActiveForm.Controls.Add(Tlačítko)

        Catch x As System.Exception

            Throw New System.Exception("Vytváření tlačítka se nezdařilo.")

        End Try

        Return True

    End Function

End Class

 

Předmětem našeho zájmu je sdílená funkce PřidatTlačítko. Signatura této sdílené funkce je značka rozsáhlá, pozůstává s množství parametrů, které specifikují:

 

 

Přidejte na formulář další instanci ovládacího prvku Button a do zpracovatele události Click této instance umístěte tento programový kód:

 

    Private Sub Button2_Click(ByVal sender As System.Object, _

    ByVal e As System.EventArgs) Handles Button2.Click

        Me.Text = CStr(TřídaB.PřidatTlačítko _

        ("btnTlačítko1", "Tlačítko", 100, 60, New Point(10, 200)))

    End Sub

 

Kód volá sdílenou metodu PřidatTlačítko třídy s názvem TřídaB. Výsledkem práce sdílené metody je vytvoření nové instance třídy Button a začlenění této instance do kolekce instancí aktuálního formuláře (tedy formuláře, jehož programový kód je právě podroben exekuci). V našem případě bude levý roh regionu instance třídy Button umístěn na bodě se souřadnicemi (10, 200), instance bude mít šířku 100 pixelů a výšku 60 pixelů. Proběhnou-li všechny operace úspěšně, sdílená funkce vrátí hodnotu True, která bude zobrazena v titulkovém pruhu aktuálního formuláře.

 

Zpět na obsah

 

Vytváření miniatur obrázků (thumbnails)

 

Grafický subsystém platformy .NET Framework s názvem GDI+ vám poskytuje relativně snadnou cestu pro vytváření grafické miniatury (thumbnail) jakéhokoliv obrázku, jehož data jsou uložena v jednom z nativně podporovaných grafických souborů. Budete-li chtít rychle vytvořit grafickou zmenšeninu vámi požadovaného obrázku, použijte následující programový kód:

 

        Dim obr As Image = Image.FromFile("c:\obr1.bmp")

        Dim th As Image = obr.GetThumbnailImage(200, 150, Nothing, IntPtr.Zero)

        Dim g As Graphics = Me.CreateGraphics

        g.DrawImage(th, 10, 10, th.Width, th.Height)

 

Uvedený kód pracuje podle tohoto algoritmu:

 

  1. Začínáme deklarací referenční proměnné obr, která může uchovávat referenci na instanci třídy Image.
  2. Jestliže předáme sdílené metodě FromFile třídy Image plně kvalifikovanou cestu k souboru s grafickými daty, tato metoda zabezpečí vytvoření instance třídy Image na řízené hromadě. Vytvořená instance bude představovat grafický objekt, jehož data byla načtena ze specifikovaného souboru.
  3. Pokračujeme deklarací další referenční proměnné th. Podobně jako proměnná obr, také proměnné th může obsahovat ukazatel na instanci třídy Image. Rozdíl mezi oběma proměnnými je však v tom, že zatímco proměnná obr obsahuje referenci na původní grafický objekt, do proměnné th bude za chvíli uložen odkaz na novou instanci třídy Image. Tato nová instance bude obsahovat grafickou miniaturu původního obrázku.
  4. Klíčem k úspěchu je nepopiratelně aktivace metody GetThumbnailImage, jejíž generická podoba je následovní:

 

Public Function GetThumbnailImage( _

   ByVal thumbWidth As Integer, _

   ByVal thumbHeight As Integer, _

   ByVal callback As Image.GetThumbnailImageAbort, _

   ByVal callbackData As IntPtr _

) As Image  

 

         Popis parametrů je uveden v tab. 1.

 

Parametr

Charakteristika

thumbWidth

Šířka miniatury grafického obrázku měřená v pixelech. 

thumbHeight

Výška miniatury grafického obrázku měřená v pixelech.

Pokud jsou hodnoty parametrů thumbWidth a thumbHeight nulové, jsou rozměry grafické miniatury určeny na základě implicitních nastavení systému.

callback

Delegát Image.GetThumbnailAbort. Ve verzi GDI+ 1.0 se tento delegát nevyužívá. Ačkoliv oficiální dokumentace říká, že je nevyhnutné delegáta vytvořit, nemusí tomu být nutně tak. V praxi totiž stačí, když do parametru callback uložíte hodnotu Nothing.

callbackData

Parametr musí obsahovat hodnotu sdíleného členu Zero struktury IntPtr. Sdílený datový člen Zero reprezentuje ukazatel, jenž byl inicializován na nulovou hodnotu. 

 

Tab. 1 – Charakteristika parametrů metody GetThumbnailImage

 

  1. Pokud je volání metody úspěšné, finálním výsledkem je instance třídy Image. Tato instance představuje grafickou miniaturu, tedy modifikovaný původní obrázek.

 

Některé grafické formáty dovolují kromě samotného grafického obrazce uložit v jednom souboru také miniaturu tohoto grafického obrazce. Pokud metoda zjistí, že soubor disponuje i grafickou miniaturou, je načtena tato miniatura. V opačném případě je zmenšen původní grafický obrazec pomocí transformačních algoritmů.

 

  1. Grafický objekt aktuální instance formuláře si připravíme pomocí metody CreateGraphics a posléze použijeme metodu DrawImage, která zabezpečí vykreslení grafické miniatury (obr. 3).

 

 

Obr. 3 – Vytvoření grafické miniatury použitím metody GetThumbnailImage

 

Zpět na obsah

 

Deklarování a generování událostí

 

Visual Basic .NET ruku v ruce s platformou .NET nabízí vývojářům množství tříd, ovládacích prvků a komponent. Instance těchto entit žijí ve světě, jenž je řízen modelem založeným na událostech. Ano, programování řízené událostmi je dnes v kurzu, a i proto se můžete takřka na každém kroku střetnout s událostmi.

 

Událost můžeme definovat jakou souhru faktorů, která nastane v jistém časovém okamžiku. Událost tak říká, že nastala jistá situace. Programové entity, jako například objekty, musí vědět, jak se mají chovat v případě, kdy nastane jistá událost. Zvyčejně objekt neví, jak na vzniklou situaci smysluplně reagovat, a proto jej to musíme naučit. Tato výuka je založená na implementaci zpracovatelů příslušných událostí. Mezi událostí a jejím zpracovatelem je zřejmý vzájemný vztah: Je to událost sama, kdo iniciuje činnost zpracovatele události, přičemž však žádný zpracovatel není aktivován do okamžiku, kdy nenastane jistá událost. V tomto tipu si ukážeme, jak pracovat s událostmi a jejími zpracovateli v programovém kódu. Uvidíte, jak se událost deklaruje a také, jak ji lze vygenerovat.

 

Postupujte následovně:

 

  1. Vytvořte nový projekt Visual Basicu .NET pro standardní aplikaci Windows (Windows Application).
  2. Na formulář přidejte instanci ovládacího prvku Button a na vytvořenou instanci poklepejte.
  3. První etapou v životním cyklu události je její deklarace. Pro deklaraci události je k dispozici příkaz Event:

 

            Public Event Událost(ByVal hwnd As Form)

 

Zde vidíte kompletní ukázku deklarace události. Před klíčovým slovem Event se nachází modifikátor přístupu události, který je v našem případě Public. Za klíčovým slovem Event se nachází název události a je jenom na vás, jak svoji událost pojmenujete (měli byste ovšem dodržovat pravidla pro pojmenovávání programových jednotek). Za názvem události následuje signatura, teda seznam parametrů, s kterým bude událost pracovat. Přesněji řečeno, s těmito parametry nebude pracovat přímo událost, ale její zpracovatel, jak sami za chvíli uvidíte. Parametry mohou být předávány hodnotou, nebo odkazem (zde je zvolen první způsob). Parametrická proměnná hwnd je schopna uchovávat ukazatel na instanci třídy Form. 

 

  1. Jakmile je událost deklarována, můžeme zařadit do kódu také zpracovatele této události. Je důležité vědět, že každá událost musí disponovat svým zpracovatelem. Ve dvojici událost -zpracovatel je právě zpracovatel tím aktivním prvkem, který iniciuje exekuci programových operací v okamžiku, kdy dojde ke generování události. Kód zpracovatele události může mít třeba tuto podobu:

 

    Public Sub Zpracovatel(ByVal hwnd As Form)

        Dim f As Integer = FreeFile()

        Try

            FileOpen(f, "d:\info.txt", OpenMode.Output, OpenAccess.Write)

            Print(f, "Handle okna: " & hwnd.Handle.ToString & _

            vbCrLf & "Titulek okna: " & hwnd.Text & _

            vbCrLf & "Neprůhlednost (%): " & (hwnd.Opacity) * 100 & _

            vbCrLf & "Výška okna (pixely): " & hwnd.Height & _

            vbCrLf & "Šířka okna (pixely): " & hwnd.Width)

            Me.Text = "Soubor s informacemi byl úspěšně vytvořen."

            FileClose(f)

        Catch x As Exception

            MessageBox.Show("Při vytváření souboru došlo k chybě.", _

            "Zpráva o chybě", MessageBoxButtons.OK, MessageBoxIcon.Error)

            Me.Text = "Soubor s informacemi nebylo možné vytvořit."

        End Try

    End Sub

 

Zpracovatel události musí mít stejnou signaturu jako samotná událost.

 

Po formální stránce je zpracovatel události Sub procedurou, což znamená, že zpracovatel události nemůže nikdy vracet žádnou návratovou hodnotu. Věřím, že výpis kódu je vám jasný na první pohled – jednoduše jsou zjištěny informace o cílové instanci třídy Form a tyto informace jsou vzápětí uloženy do textového souboru na logický oddíl pevného disku.   

 

  1. Po deklaraci události a implementaci jejího zpracovatele je načase vytvořit mezi těmito dvěma entitami přepojení. Toto přepojení je velmi důležité proto, aby událost mohla najít svého zpracovatele. Z pohledu tvorby zdrojového kódu je přepojení mezi událostí a jejím zpracovatele realizováno prostřednictvím příkazu AddHandler:

 

    

    Private Sub Form1_Load(ByVal sender As Object, _

    ByVal e As System.EventArgs) Handles MyBase.Load

 

        AddHandler Událost, AddressOf Zpracovatel

 

    End Sub

 

Jelikož není možné vytvořit přepojení mezi událostí a jejím zpracovatelem ve fázi psaní kódu, musí být toto přepojení vytvořeno až za běhu programu. Z tohoto důvodu se kód příkazu AddHandler nachází v událostní proceduře Form1_Load.    

 

Tento řádek kódu naznačuje, že při startu aplikace bude vytvořen vztah mezí událostí a jejím zpracovatelem. Ve skutečnosti je situace komplikovanější, protože Visual Basic .NET automaticky vytvoří delegáta, který obsahuje adresu zpracovatele události. Pokud byste programovali například v C#, museli byste příslušného delegáta explicitně deklarovat, ovšem Visual Basic .NET tuto operaci provádí za vás, a tím minimalizuje vaše programátorské úsilí.

 

  1. Nakonec zbývá už jenom vygenerovat událost. Událost může být generována takřka kdykoliv, závisí tedy jenom na programátorovi, kdy bude chtít událost generovat. Generování událostí je realizováno použitím příkazu RaiseEvent:

 

    Private Sub Button1_Click(ByVal sender As System.Object, _

    ByVal e As System.EventArgs) Handles Button1.Click

 

        RaiseEvent Událost(Me)

 

    End Sub

 

Za příkazem RaiseEvent následuje název události, kterou chceme generovat. Pokud událost pracuje s parametry, je nutné tyto patřičně naplnit. Jak si můžete všimnout, událost bude generována v okamžiku, kdy uživatel klepne na tlačítko Button1 (události mohou být samozřejmě vyvolávány také při mnoha dalších příležitostech).

 

Zpět na obsah

 

 

Právě jste dočetli poslední tip sekce Programátorská laboratoř. 

 

Jestliže se chcete dozvědět více informací o programování ve Visual Basicu .NET, neváhejte a navštivte také další sekce rubriky Visual Basic. A jakáže je dnešní nabídka?

Téma měsíce

Inteligentní značky (Smart Tags)

Seriál Začínáme s VB .NET

Porovnávací operátory Is a Like, přiřazovací operátory...