Integrované prostředí rubriky Visual Basic |
Autor: Ján Hanák |
||||||||
|
Programátorská laboratoř |
||||||||
Prostor pro experimentování |
|||||||||
Časová náročnost (min): 75 |
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ý |
|||||||
|
Nepřehlédněte exkluzivní
Speciál pro programátory, který pojednává o jazykové interoperabilitě mezi
jazyky Managed Extensions for C++ a Visual Basic .NET. |
||||||||
|
Tvorba zapečetěné třídy
V jistých situacích je pro programátora
nežádoucí, aby třída, kterou vytvořil svými vlastními silami, byla zdrojem pro
další odvozené třídy. Jestliže programátor použije v deklaraci třídy
klíčové slovo NotInheritable, výslovně nařizuje, že daná třída nemůže sloužit jako bázová třída.
Třídě s uvedenými charakteristikami se říká zapečetěná třída. Pokud
porovnáme standardní třídu a její zapečetěnou kolegyni, můžeme pozorovat, že primárním
rozdílem mezi těmito dvěma třídami je jejich chování při dědění.
|
Pod pojmem „standardní třída“ budeme v následujícím textu rozumět
třídu, v deklaraci které se nenachází klíčové slovo NotInheritable,
jakožto ani jiné modifikátory, které jakýmkoliv způsob ovlivňují chování
třídy. |
Zatímco od standardní třídy můžeme odvodit
tolik podtříd, kolik budeme chtít, zapečetěná třída touto dovedností
nedisponuje. Ovšem obě třídy mohou vytvářet své instance, v tomto směru se
zapečetěná třída chová úplně stejně jako její standardní protějšek.
I když není tvorba zapečetěné třídy zcela
běžnou záležitostí, existuje několik pádných důvodů pro označení třídy klíčovým
slovem NotInheritable:
Zapečetěné třídy jsou zpravidla třídy, jejichž
stavba plně pokrývá vyřešení jisté problematiky. Jednoduše řečeno, zapečetěná
třída obsahuje všechny prvky (vlastnosti, metody a datové členy), které budou
instance této třídy využívat. Zapečetěná třída je tak daleko objemnější a
robustnější jako jakákoliv jiná třída. Tato skutečnost vyplývá právě
z faktu, že zapečetěná třída si „veze všechno s sebou“. Abyste viděli
hlavní rozdíly mezi návrhem a tvorbou standardní a zapečetěné třídy, uveďme si
některé podstatné znaky (tab. 1).
Komparační
znaky |
Typ
třídy |
|
Standardní
třída |
Zapečetěná
třída |
|
Proces
návrhu |
Při návrhu
standardní třídy je ve většině případů brán do úvahy požadavek na pozdější
rozšiřitelnost třídy pomocí dědičnosti, a proto se standardní třída navrhuje
jako bázová třída. To znamená, že do bázové třídy je zařazena pouze všeobecná,
resp. základní funkcionalita, ovšem veškeré konkrétní nebo specifické rysy
jsou implementovány až v odvozených třídách. |
Proces návrhu
zapečetěné třídy musí pozůstávat z pečlivé analýzy všech aspektů
funkcionality této třídy. Protože charakter zapečetěné třídy nemůže být později
rozšířen v podtřídách, musí zapečetěná třída obsahovat všechny členy,
které budou instance této třídy ke své práci potřebovat. |
Dědičnost |
Odvozené třídy
vznikají na základě techniky jednoduché dědičnosti, která je přímo
podporována platformou .NET (přesněji společnou jazykovou specifikací –
Common Language Specification).
Standardní třída není v procesu dědění nijak omezena, a proto je možné
vytvářet libovolné množství podtříd. |
Zapečetěná třída
dědičnost nepodporuje, což znamená, že nemůže sloužit jako bázová třída pro
tvorbu odvozených tříd. |
Rozšíření |
Rozšíření standardní
třídy může v zásadě probíhat ve dvou směrech: ·
rozšíří
se přímo programový kód standardní třídy ·
rozšíření
se uskuteční upravením programového kódu odvozených tříd |
Rozšíření zapečetěné
třídy se musí uskutečnit prostřednictvím začlenění dodatečného programového
kódu do samotné zapečetěné třídy. |
Vytváření
instancí |
Plná podpora
vytváření instancí třídy.* |
Plná podpora
vytváření instancí třídy.* |
* Za předpokladu, že
programátor nezačlenil do kódu třídy privátní konstruktor. |
* Za předpokladu, že
programátor nezačlenil do kódu třídy privátní konstruktor. |
Tab. 1 – Komparace standardní a zapečetěné třídy
Na následujících řádcích je uveden výpis
zdrojového kódu zapečetěné třídy:
Option Strict
On
Public NotInheritable
Class ZapečetěnáTřída
Private
m_Počet As Byte
Public Property ZjistitPočetFormulářů() As Byte
Get
Return
m_Počet
End Get
Set(ByVal Value As Byte)
m_Počet = Value
End Set
End Property
Public Sub VytvořitFormuláře(ByVal
Počet As Byte)
m_Počet = Počet
If
Počet <= 0 Or Počet > 10 Then
MessageBox.Show("Bylo zadáno
nevhodné číslo (" & Počet _
& ") pro počet formulářů."
& vbCrLf & _
"Nyní bude zobrazen dialog, v
němž budete moci zadat " & _
"správné číslo pro počet
formulářů.", "Zpráva o chybě", _
MessageBoxButtons.OK,
MessageBoxIcon.Error)
Dim
odp As Byte = CByte(InputBox _
("Zadejte číslo pro počet
formulářů (<1, 10>).", _
"Určení počtu formulářů",
"1"))
Počet = odp
GoTo
Tvorba_Formulářů
Else
Tvorba_Formulářů:
Dim
a As Byte
Dim
frm(Počet - 1) As Form
For
a = 0 To CByte(Počet
- 1)
frm(a) = New Form()
With
frm(a)
.Text = "Formulář č.
" & a + 1
.Show()
End
With
Application.DoEvents()
Next
End If
End Sub
End Class
Ukázková zapečetěná třída slouží na vytváření
polí instancí třídy Form. Jak si můžete všimnout, v těle
třídy se nachází veřejná metoda VytvořitFormuláře, která odvádí
veškerou potřebnou práci. Počet vytvořených formulářů je uložen do soukromého
datového členu s názvem m_Počet. Hodnotu členu m_Počet lze získat zavoláním veřejné vlastnosti ZjistitPočetFormulářů. Věřím, že jako profesionálním programátorům je vám kód zapečetěné
třídy víceméně jasný, ovšem chtěl bych vás upozornit na tyto skutečnosti:
|
Všimněte si, že v kódu není proveden test návratové hodnoty
funkce InputBox (jednoduše předpokládáme, že uživatel zadá správnou
hodnotu z ohraničeného celočíselného intervalu). Pokud bude tento kód
používat v reálných aplikacích, ujistěte se, že jste provedli také test
návratové hodnoty funkce InputBox. A to z toho důvodu, že i když
se uživatel již jednou zmýlil, není vůbec vyloučeno, že tak udělá i
podruhé. |
K použití instance zapečetěné třídy nám
bude stačit několik řádků programového kódu:
Dim x As New
ZapečetěnáTřída()
x.VytvořitFormuláře(3)
Me.Text
= "Počet vytvořených formulářů: " & _
CStr(x.ZjistitPočetFormulářů)
Přístup k registrům operačního systému Windows
Snad všichni programátoři a vývojáři chtějí,
aby byly jejich aplikace co možná nejvíc uživatelsky přívětivé. Uživatelská
přívětivost je značně rozsáhlý pojem, jenž v sobě absorbuje velké množství
doporučených standardů, které říkají, jak má aplikace vypadat a jak se má
chovat. Dodržováním těchto standardů tak mohou programátoři zabezpečit, že
uživatelům se bude s aplikací pracovat pohodlně, rychle a bez jakýchkoliv
potíží. Jedním z požadavků, které jsou na reálnou aplikaci kladeny, je
schopnost aplikace pamatovat si potřebné informace o stavech, v nichž se
během své činnosti ocitla. Tak si aplikace může pamatovat seznam posledně
otevřených souborů, přesnou pozici svého dialogového okna, nebo časový interval
pro automatické uložení editovaného dokumentu. Na uložení a posléze načítaní
všech uvedených informací lze s výhodou využít registrů operačního
systému.
Ve Visual Basicu .NET můžeme aplikovat dvě
koncepce přístupu k registrům:
Abyste viděli, jak obě koncepce pracují,
ukážeme si jejich použití v praxi. Pokaždé provedeme vytvoření registrového
klíče, jemuž přiřadíme příslušnou hodnotu a tuto hodnotu naplníme předem
určenými daty.
|
Při práci s registry je zapotřebí odlišovat dva pojmy: jméno
hodnoty a data hodnoty. Zatímco jméno hodnoty představuje textový řetězec,
který hodnotu uživatelsky deklaruje, data hodnoty determinují hodnotu po
datové stránce. Jednoduše řečeno, data hodnoty jsou vlastnictvím hodnoty, a
jsou to právě data, které jsou předmětem vstupně-výstupních operací při práci
s registry. Mezi data hodnoty mohou patřit čísla, textové řetězce, nebo
specifické konstanty. |
|
Registry operačního systému jsou velmi důležitou entitou, a to jak ve
vztahu k nainstalovaným aplikacím, tak i vůči samotnému operačnímu
systému. Před zásahem do registrů proveďte vždy nejprve jejich zálohu. Při
zásazích do registrů se ujistěte, že nemodifikujete údaje, které byly zapsány
jinou aplikací a přímo upravujte jenom ty informace, které jste do registrů sami
zapsali. |
Demonstrace staré koncepce přístupu k registrům
Postupujte podle následujících instrukcí:
Private Sub btnZápisHodnot_Click(ByVal
sender As System.Object, _
ByVal e As System.EventArgs) Handles
btnZápisHodnot.Click
SaveSetting("MojeAplikace",
"Data", "ID aplikace", "1001")
End Sub
Private Sub btnČteníHodnot_Click(ByVal
sender As System.Object, _
ByVal e As System.EventArgs) Handles
btnČteníHodnot.Click
MessageBox.Show("ID aplikace je:
" & _
GetSetting("MojeAplikace",
"Data", "ID aplikace"))
End Sub
Obr. 1 – Použití funkcí SaveSetting a GetSetting
pro přístup k hodnotě uložené v registrech
Demonstrace nové koncepce přístupu k registrům
Jak jsme si již řekli, při použití této
koncepce se vyhneme použití funkcí typu SaveSetting a GetSetting. Místo nich totiž povoláme
k práci specializované třídy Registry a RegistryKey z jmenného prostoru Microsoft.Win32. Postupujte
takto:
Imports
Microsoft.Win32
Private Sub btnZápisHodnot2_Click(ByVal
sender As System.Object, _
ByVal e As System.EventArgs) Handles
btnZápisHodnot2.Click
Dim reg
As RegistryKey
reg =
Registry.LocalMachine.CreateSubKey("Software\MojeAplikace\Data")
reg.SetValue("ID aplikace",
"1002")
End Sub
Pohled do registrů přibližuje obr. 2.
Obr. 2 – Použití tříd Registry
a RegistryKey pro přístup k hodnotě uložené v registrech
I když opět vytváříme klíč se stejným názvem,
v tomto případě je klíč uložen do jiné sekce registrů (přesněji do HKEY_LOCAL_MACHINE\Software). Abychom získali přístup do této sekce registrů, musíme použít třídu Registry a její veřejný sdílený datový člen LocalMachine. Pro vytvoření nového klíče použijeme metodu CreateSubKey, které předáme doplňkovou cestu ke klíči v uvedené podobě (plná
cesta k našemu klíči vypadá takto: HKEY_LOCAL_MACHINE\Software\MojeAplikace\Data). Návratovou hodnotou metody CreateSubKey je instance třídy RegistryKey, přičemž odkaz na tuto instanci je
uložen do proměnné reg. Dobrá,
v této chvíli máme vytvořen klíč, ovšem náš úkol ještě není splněn.
Abychom klíči přiřadili hodnotu a hodnotu asociovali s platnými daty,
zavoláme metodu SetValue,
která nabídneme jméno hodnoty ve tvaru datového typu String ("ID aplikace") a data hodnoty (1002).
Budete-li chtít data hodnoty načíst, upravte událostní
proceduru btnČteníHodnot2_Click tak, jak je uvedeno
níže:
Private Sub
btnČteníHodnot2_Click(ByVal sender As System.Object, _
ByVal e As
System.EventArgs) Handles btnČteníHodnot2.Click
Dim
reg2 As RegistryKey
reg2 =
Registry.LocalMachine.OpenSubKey("Software\MojeAplikace\Data", False)
MessageBox.Show("Hodnota
zapsaná v registrech: " & _
CStr(reg2.GetValue("ID
aplikace")))
End Sub
Abychom otevřeli požadovaný registrový klíč, zavoláme metodu OpenSubKey. V našem případě je použita přetížená varianta metody, která
pracuje se dvěma parametry: prvním je název klíče a druhým pak booleovská
hodnota, která určuje, zdali je možné hodnotu klíče modifikovat. K datům
hodnoty se dostaneme pomocí metody GetValue, která
poskytneme jméno hodnoty, data které chceme obdržet. Metoda GetValue vrací data hodnoty (v podobě datového typu Object), která jsou v naší ukázce přetypována do podoby datového typu String a zobrazena v dialogu.
Vytváření vlastního delegáta
Přecházíte-li na programování pro platformu .NET, zcela jistě si
zanedlouho všimnete speciálního programovacího aparátu, který se doposud
v programování nevyskytoval. Ano, touto novinkou jsou delegáti, neboli
objekty, které usnadňují přístup k metodám a funkcím jiných objektů za běhu
programu. O delegátech se často mluví jako o typově bezpečných funkčních
ukazatelích. Pokud patříte mezi programátory v C/C++, mohli byste namítat,
že funkční ukazatele jsou tady již nějaký ten pátek, tak jakážto novinka. Ovšem,
v jistém smyslu máte pravdu, avšak třeba zdůraznit, že delegáty nabízejí
daleko větší funkcionalitu nežli opravdové funkční ukazatele. Kromě toho,
s delegáty můžete pracovat v mnoha .NET jazycích, např. v C# či
Managed Extensions for C++.
V dnešní ukázce si předvedeme, jak sestrojit vlastního delegáta.
Ještě předtím se však podívejme na základní způsob práce delegáta. Delegát je
objekt, jenž může za běhu aplikace získat runtime adresu požadované procedury a
posléze tuto proceduru aktivovat. Ve skutečnosti ovšem může delegát aktivovat
jakoukoliv proceduru, která má stejný seznam parametrů a stejnou návratovou
hodnotu jako samotný delegát. Delegát tak nemusí nutně volat jednu a tu samou
proceduru, neboť je schopen aktivovat libovolnou proceduru, která vyhovuje
požadovaným podmínkám. Rozhodnutí, kterou proceduru zavolat, lze vyřešit až za
běhu aplikace.
Obr. 3 – Schematické
znázornění práce delegáta
A nyní si ukažme, jak přistoupit k tvorbě delegáta:
Option Strict
On
'Vložené
odkazy na potřebné jmenné prostory.
Imports System.Drawing
Imports System.Drawing.Drawing2D
Public Class
Form1
Inherits
System.Windows.Forms.Form
'Deklarace
delegáta.
Private Delegate Function
Delegát() As Boolean
'****** Deklarace
první cílové funkce. ******
'Funkce vytváří
instanci třídy ListBox, do které budou uložena
'náhodně
vygenerovaná čísla.
Private Function MojeFunkce() As
Boolean
Try
'Vytvoření
instance třídy ListBox a její umístění
'do
kolekce ovládacích prvků formuláře.
Dim
lstSeznam As New
ListBox()
With
lstSeznam
.Location = New Point(0, 0)
.Size = New Size(Me.Width \ 2, Me.Height \ 2)
End
With
Me.Controls.Add(lstSeznam)
'Výpočet
druhé mocniny čísel z intervalu <0, 9>.
Dim
a As Byte
a = 0
Do While a < 10
Dim
x As Short
x = CShort(a
^ 2)
lstSeznam.Items.Add(x)
a += CByte(1)
Loop
'Zachycení
jakékoliv výjimky, která by mohla být generována.
Catch e
As Exception
'Dojde-li
k chybě, funkce je ukončena a vrací hodnotu False.
Return
False
End Try
'Při úspěšném
ukončení funkce je vrácena hodnota True.
Return True
End Function
'****** Deklarace
druhé cílové funkce. ******
'Funkce vyplňuje
plochu formuláře gradientní výplní.
Private Function MojeKreslícíFunkce() As Boolean
Try
'Vytvoření
instance třídy Rectangle
Dim
rec As New
Rectangle(New Point(0, 0), _
New
Size(Me.Width, Me.Height))
'Vytvoření
grafického štětce pomocí třídy LinearGradientBrush
Dim
br As New
LinearGradientBrush(rec, Color.Gold, _
Color.Magenta,
LinearGradientMode.ForwardDiagonal)
'Vytvoření
grafického objektu
Dim
g As Graphics = Me.CreateGraphics()
'Kreslení
gradientní výplně.
g.FillRectangle(br, rec)
Catch e
As Exception
'Dojde-li
k chybě, funkce je ukončena a vrací hodnotu False.
Return
False
End Try
'Při úspěšném
ukončení funkce je vrácena hodnota True.
Return True
End Function
Private Sub Form1_Click(ByVal
sender As Object,
_
ByVal e As System.EventArgs) Handles
MyBase.Click
'Inicializace
generátoru náhodných čísel na bázi systémového času
Randomize()
'Deklarace
proměnné, ve které bude uloženo získané
'náhodné
číslo
Dim sHodnota As Short
'Vytvoření
referenční proměnné, která bude uchovávat odkaz
'na později
vytvořenou instanci delegáta
Dim
InstanceDelegáta As Delegát
'Generování
náhodného čísla z intervalu <1,10>
sHodnota = CShort(Int(10
* Rnd()) + 1)
'Jestliže je
vygenerované číslo z intervalu <1,5> tak...
If
sHodnota >= 1 And sHodnota <= 5 Then
'Vytvoření
instance delegáta, která obsahuje
'runtime
adresu funkce MojeFunkce
InstanceDelegáta = New
Delegát(AddressOf MojeFunkce)
'jinak...
Else
'Vytvoření
instance delegáta, která obsahuje runtime
'adresu
funkce MojeKreslícíFunkce
InstanceDelegáta = New Delegát(AddressOf
MojeKreslícíFunkce)
End If
'Test
návratové hodnoty cílové funkce
If
InstanceDelegáta.Invoke() Then
Me.Text
= "Funkce byla úspěšně zavolána."
Else
Me.Text
= "Při práci funkce došlo k potížím."
End If
End Sub
End Class
|
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? |
|
Programování vícevláknových aplikací |
||
Klasifikace
operátorů, aritmetické a porovnávací operátory. |
Nepřehlédněte exkluzivní
Speciál pro programátory, který pojednává o jazykové interoperabilitě mezi
jazyky Managed Extensions for C++ a Visual Basic .NET. |