5. Vytváření metod

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;
}

  1. Č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áí?

  2. 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.
  3. 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á.

  4. 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.
  5. 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.

  6. 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();
    };
  7. 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:

  8. AboutBoxDlg1->Execute();
    a spustíme aplikaci. Můžeme také vyzkoušet nastavit různé vlastnosti komponenty.
5. Vytváření metod