Metody komponent se neliší od ostatních metod objektu.
Jsou to funkce zabudované ve struktuře třídy komponenty. I když nejsou
žádná omezení na to, co můžeme dělat s metodami komponenty, C++ Builder
používá některé standardy. Tento návod se zabývá:
Obecně, komponenty nemívají mnoho metod a měli bychom minimalizovat
počet metod, které aplikace může volat. Služby které by mohly být implementované
jako metody je často lepší realizovat pomocí událostí. Události poskytují
rozhraní, které odpovídá prostředí C++ Builderu a je přístupné při návrhu.
Zabránění závislostem
Vždy, když zapisujeme komponentu minimalizujeme podmínky
vkládané na uživatele komponenty. Do nejvyšší míry by měl být uživatel
komponenty schopný dělat cokoli s komponentou a kdykoli to chce. Jsou situace,
kdy toto nelze splnit, ale našim cílem je nejvíce se k tomu přiblížit.
Přestože je nemožné vypsat všechny druhy závislostí, kterým se chceme vyhnout,
následující seznam uvádí to čemu se máme vyhýbat: Metodám, které uživatel
musí volat, aby mohl používat komponentu, metodám, které musí být použity
v určitém pořadí a metodám, které způsobí, že určité události nebo metody
mohou být chybné.
Např. když vyvolání metody způsobí, že naše komponenta
přejde do stavu, kdy volání jiné metody může být chybné, pak napíšeme tuto
jinou metodu tak, aby když ji uživatel zavolá a komponenta je ve špatném
stavu, pak metoda opraví tento stav před provedením vlastního kódu. Minimálně
bychom měli zajistit generování výjimky v případech, kdy uživatel použije
nedovolenou metodu. Jinými slovy, jestliže vytvoříme situaci, kde části
našeho kódu jsou vzájemně závislé, musíme zajistit, aby používání kódu
chybným způsobem nezpůsobilo uživateli problémy. Varování je lepší než
havárie systému, když se uživatel nepřizpůsobí našim vzájemným závislostem.
Pojmenovávání metod
C++ Builder neklade žádná omezení na jména metod a jejich
parametrů. Nicméně je několik konvencí, které usnadňují používání metod
pro uživatele naších komponent. Je vhodné dodržovat tato doporučení: Volíme
popisná jména. Jméno jako PasteFromClipboard je mnohem více informativní
než jednoduché
Paste nebo PFC. Ve jménech svých metod používáme
slovesa. Např. ReadFileNames je mnohem srozumitelnější než DoFiles.
Jména metod by měla vyjadřovat, co vracejí. Přestože metodu vracející vodorovnou
souřadnici něčeho můžeme nazvat X, je mnohem výhodnější použít jméno
GetHorizontalPosition.
Ujistěte se, že metody skutečně musí být metodami. Dobrá pomůcka je, že
jméno metody obsahuje sloveso. Jestliže vytvoříme několik metod, jejich
jméno neobsahuje sloveso, zamyslete se nad tím, zda by tyto metody nemohly
být vlastnostmi.
Chránění metod
Všechny části tříd, včetně datových složek, metod a vlastností
mohou mít různé úrovně přístupu. Volba vhodné úrovně přístupu pro metody
je jednoduchá. Metody které zapisujeme ve svých komponentách jsou veřejné
nebo chráněné. Není žádný důvod pro vytváření soukromých nebo zveřejňovaných
metod.
Všechny metody, které uživatelé našich komponent mohou
volat, musí být veřejné. Musíme mít na paměti, že mnoho metod je voláno
v obsluhách událostí, a tak metody by se měli vyhnout plýtváním systémovými
zdroji nebo uvedením Windows do stavu, kdy nemůže reagovat. Konstruktory
a destruktory musí být vždy veřejné.
Metody, které jsou implementačními metodami pro komponentu,
musí být chráněné. To zabrání uživateli v jejich volání v nesprávný čas.
Jestliže máme metody, které uživatelský kód nesmí volat, ale objekty potomků
volat mohou, pak metody deklarujeme jako chráněné. Např. předpokládejme,
že máme metodu která spoléhá na nastavení jistých dat předem. Jestliže
tuto metodu uděláme veřejnou, umožníme tím uživateli, aby ji volat i před
nastavením potřebných dat. Pokud ale bude chráněná, zajistíme tím, že uživatel
ji nemůže volat přímo. Můžeme pak vytvořit jinou veřejnou metodu, která
zajistí nastavení dat před voláním chráněné metody.
Metod, které musí být vždy virtuální a chráněné, jsou
implementační metody vlastností. Zajišťují, že jediný přístup k informacím
vlastností je prostřednictvím samotné vlastnosti.
Dělání virtuálních metod
Virtuální metody v komponentách C++ Builderu se neliší od
virtuálních metod v jiných třídách. Metodu uděláme virtuální, když chceme
aby různé typy byly schopny provést různý kód v reakci na stejné funkční
volání. Jestliže vytváříme komponentu určenou pouze k přímému použití koncovým
uživatelem, uděláme pravděpodobně všechny její metody nevirtuální. Na druhé
straně, jestliže vytváříme komponentu více abstraktní povahy, kterou jiní
tvůrci komponent mohou použít jako počáteční bod pro své vlastní komponenty,
zvážíme vytvoření virtuálních metod. Komponenty odvozené od naší komponenty
pak mohou předefinovat zděděné virtuální metody.
Deklarování metod
Deklarování metod v komponentách se neliší od deklarování
metod v jiných třídách. Při deklaraci nové metody v komponentě provedeme
dvě věci: přidáme její deklaraci k deklaraci třídy komponenty a implementujeme
metodu v souboru CPP jednotky komponenty.
Následující kód ukazuje komponentu, která definuje dvě
nové metody: jednu chráněnou metodu a jednu veřejnou virtuální metodu.
class PACKAGE TPrikladKomponenty : public
TControl
{
protected:
void __fastcall Zvetsi();
public:
virtual int __fastcall VypoctiOblast();
};
V CPP souboru je implementace metod:
void __fastcall TPrikladKomponenty::Zvetsi()
{
Height = Height + 5;
Width = Width + 5;
}
int __fastcall TPrikladKomponenty::VypoctiOblast()
{
return Width * Height;
}
-
Často používané komponenty dialogových oken můžeme také přidat na Paletu
komponent. Naše komponenta dialogového okna bude pracovat stejně jako komponenty,
které reprezentují standardní dialogová okna Windows. Vytvoření komponenty
dialogového okna vyžaduje čtyři kroky: definování rozhraní komponenty,
vytvoření a registraci komponenty, vytvoření rozhraní komponenty a testování
komponenty. Cílem je vytvořit jednoduchou komponentu, kterou uživatel může
přidat k projektu a nastavit její vlastnosti během návrhu. ?Obalovací
komponenta C++ Builderu přiřazená k dialogovému oknu je vytvoří a provede
při běhu aplikace a předá data definovaná uživatelem. Komponenta dialogového
okna je tedy zase opětovně použitelná a přizpůsobitelnáí?
Ukážeme si jak vytvořit obalovou komponentu okolo obecného formuláře
About
obsaženého v Zásobníků objektů C++ Builderu. Nejprve zkopírujeme soubory
ABOUT.H,
ABOUT.CPP
a ABOUT.DFM do našeho pracovního adresáře. ABOUT.CPP
vložíme
do nějaké aplikace a provedeme překlad. Tím vytvoříme soubor
ABOUT.OBJ,
který budeme potřebovat při vytváření komponenty.
-
Dříve než můžeme vytvořit komponentu pro naše dialogové okno, musíme určit
jak chceme, aby ji vývojář používal. Vytvoříme rozhraní mezi našim dialogovým
oknem a aplikací, která jej používá.
Např. podívejme se na vlastnosti komponent standardních dialogových
oken. Umožňují vývojáři nastavovat počáteční stav dialogového okna, jako
je titulek a počáteční nastavení ovladačů, a po uzavření dialogového okna
převzít zpět požadované informace. Není to přímá interakce s jednotlivými
ovladači v dialogovém okně, ale s vlastnostmi v obalové komponentě.
Rozhraní tedy musí obsahovat požadované informace, které formulář dialogového
okna může zobrazit a vracet aplikaci. Můžeme si představit vlastnosti obalové
komponenty jako data přenášená z a do dialogového okna.
V případě okna
About, nepotřebujeme vracet žádné informace a
tedy vlastnosti obalové komponenty obsahují pouze informace požadované
k zobrazení v okně. Jsou to čtyři položky dialogového okna About,
které aplikace může ovlivnit a poskytneme tedy čtyři vlastnosti typu řetězec.
Obvyklým způsobem vytvoříme komponentu. Zadáme tato specifika: programovou
jednotku komponenty nazveme AboutDlg, od TComponent odvodíme
nový typ komponenty TAboutBoxDlg a registrujeme vytvářenou komponentu
na stránce Samples Palety komponent. Po provedení těchto akcí dostaneme:
#ifndef AboutDlgH
#define AboutDlgH
#include <vcl\sysutils.hpp>
#include <vcl\controls.hpp>
#include <vcl\classes.hpp>
#include <vcl\forms.hpp>
class PACKAGE TAboutBoxDlg : public TComponent
{
private:
protected:
public:
__fastcall TAboutBoxDlg(TComponent*
Owner);
__published:
};
#endif
CPP soubor vypadá takto:
#include <vcl\vcl.h>
#pragma hdrstop
#include "AboutDlg.h"
#pragma package(smart_init);
static inline TAboutBoxDlg *ValidCtrCheck()
{
return new TAboutBoxDlg(NULL);
}
__fastcall TAboutBoxDlg::TAboutBoxDlg(TComponent*
Owner)
: TComponent(Owner)
{
}
namespace Aboutdlg
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TAboutBoxDlg)};
RegisterComponents("Samples", classes,
0);
}
}
Nová komponenta má nyní pouze možnosti zabudované do TComponent.
Je to nejjednodušší nevizuální komponenta.
-
Když již máme vytvořenou komponentu a definované rozhraní mezi komponentou
a dialogovým oknem, můžeme implementovat její rozhraní. To provedeme ve
třech krocích: vložíme jednotku formuláře, přidáme vlastnosti rozhraní
a přidáme metodu Execute.
Pro naší obalovou komponentu k inicializaci a zobrazení obaleného dialogového
okna musíme přidat soubory formuláře k projektu. Vložíme tedy ABOUT.H
a sestavení s ABOUT.OBJ do hlavičkového souboru komponenty:
#include "About.h"
#pragma link "About.obj"
Hlavičkový soubor formuláře vždy deklaruje instanci třídy formuláře.
V případě okna About, je třída formuláře TAboutBox a soubor
ABOUT.H
obsahuje následující deklaraci:
extern TAboutBox *AboutBox;
Vlastnosti v obalové komponentě jsou jednodušší než vlastnosti v normální
komponentě. Umožňují pouze předávání dat mezi obalovou komponentou a dialogovým
oknem. Vložením dat do vlastností formuláře, povolíme vývojáři nastavit
data během návrhu pro obal k jejich předání do dialogového okna při běhu
aplikace.
Deklarace vlastností rozhraní vyžaduje dvě další deklarace v typu komponenty:
soukromou položku, kterou obal použije k uložení hodnoty vlastnosti a samotnou
zveřejňovanou deklaraci vlastnosti, která specifikuje jméno vlastnosti
a říká která položka je použita pro uložení. Vlastnosti rozhraní nevyžadují
přístupové metody. Používají přímý přístup ke svým datům. Podle konvencí
má objektová položka pro uložení hodnoty vlastnosti stejné jméno jako vlastnost,
ale na začátku je přidáno písmeno F. Datová položka a vlastnost
musí být stejného typu.
Např. k deklaraci vlastnosti rozhraní celočíselného typu nazvané Rok,
použijeme:
class PACKAGE TMujObal : public TComponent
{
private:
int FRok;
__published:
__property int Rok = {read=FRok, write=FRok};
}
Pro dialogové okno About potřebujeme čtyři vlastnosti typu String,
po jedné pro jméno produktu, informaci o verzi, autorských právech a komentář.
Soubor ABOUTDLG.H nyní vypadá takto:
class PACKAGE TAboutBoxDlg : public TComponent
{
private:
String FProductName, FVersion, FCopyright,
FComments;
__published:
__property String ProductName={read=FProductName,
write=FProductName};
__property String Version = {read=FVersion,
write=FVersion};
__property String Copyright = {read=FCopyright,
write=FCopyright};
__property String Comments = {read=FComments,
write=FComments};
};
Když nyní instalujeme komponentu na paletu a umístíme ji na formulář,
můžeme nastavovat vlastnosti a tyto hodnoty jsou automaticky předávány
s formulářem. Tyto hodnoty budou použity při provádění dialogového okna.
Poslední částí rozhraní komponenty je otevření dialogového okna a vrácení
výsledku při jeho uzavření. Komponenty obecných dialogových oken používají
logickou funkci nazvanou Execute, která vrací true, jestliže
uživatel stiskl OK nebo false, když uživatel okno zrušil.
Deklarace pro metodu Execute je vždy tato:
class PACKAGE TMujObal : public TComponent
{
public:
bool __fastcall Execute();
}
Minimální implementace pro Execute vyžaduje vytvoření formuláře
dialogového okna, jeho zobrazení jako modálního dialogového okna a vrácení
true
nebo false (v závislosti na návratové hodnotě ShowModal).
Následuje minimální metoda Execute pro formulář dialogového
okna typu TMojeDialOkno:
bool __fastcall TMujObal::Execute()
{
bool Result;
DialOkno = new TMojeDialOkno(Application);
try
{
Result = (DialOkno->ShowModal()
== IDOK)
}
catch(...)
{
Result = false;
}
DialOkno->Free();
}
V praxi, bývá více kódu uvnitř bloku try..catch. Před voláním
ShowModal,
obal nastaví nějaké vlastnosti dialogového okna na základě vlastností rozhraní
obalové komponenty. Po návratu z ShowModal, obal pravděpodobně nastaví
některé své vlastnosti rozhraní na základě provedení dialogového okna.
V případě okna About, použije obalová komponenta čtyři vlastnosti
rozhraní k nastavení obsahu formuláře dialogového okna
About. Jelikož
okno About nevrací žádné informace, není nutno provádět nic po volání
ShowModal.
Naše metoda Execute bude tedy vypadat takto:
bool __fastcall TAboutBoxDlg::Execute()
{
bool Result;
AboutBox = new TAboutBox(Application);
try
{
if (ProductName == "")
ProductName = Application->Title;
AboutBox->ProductName->Caption
= ProductName;
AboutBox->Version->Caption
= Version;
AboutBox->Copyright->Caption
= Copyright;
AboutBox->Comments->Caption
= Comments;
AboutBox->Caption = "About
"+ ProductName;
Result = (AboutBox->ShowModal()
== IDOK);
}
catch(...)
{
Result = false;
}
AboutBox->Free();
return Result == IDOK;
}
K hlavičkovému souboru ABOUTDLG.H přidáme deklaraci metody Execute
do veřejné části třídy TAboutDlg.
class PACKAGE TAboutDlg : public TComponent
{
public:
virtual bool __fastcall Execute();
};
-
Když instalujeme komponentu dialogového okna, můžeme ji používat stejně
jako obecná dialogová okna, umístěním na formulář a jejich provedením.
Rychlý způsob k otestování okna About je přidat na formulář tlačítko
a provést dialogové okna při stisknutí tohoto tlačítka. Testování naší
komponenty lze provést v těchto krocích: vytvoříme nový projekt, umístíme
komponentu okna About a komponentu tlačítka na formulář, dvojitě
klikneme na tlačítko (vytvoříme prázdnou obsluhu události stisku tlačítka),
do obsluhy události stisku tlačítka zapíšeme následující řádek kódu:
AboutBoxDlg1->Execute();
a spustíme aplikaci. Můžeme také vyzkoušet nastavit různé vlastnosti
komponenty.