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
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ě:
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ě.
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.
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.
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:
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
|
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ů. |
Obr. 3 – Vytvoření grafické
miniatury použitím metody GetThumbnailImage
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ě:
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.
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.
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í.
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).
|
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? |
|
Inteligentní značky (Smart Tags) |
||
Porovnávací operátory Is a Like, přiřazovací operátory... |