11. T°φdy v C++ Builderu I
  1. Vra╗me se k na╣emu prvnφmu programu, kter² jsme v  vytvo°ili (formulß° s tlaΦφtkem m∞nφcφm barvu formulß°e na zelenou). Zdrojov² text tohoto programu je (hlaviΦkov² a CPP soubor):

  2. #ifndef Unit1H
    #define Unit1H
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    class TForm1 : public TForm
    {
    __published:    // IDE-managed Components
     TButton *Button1;
     void __fastcall Button1Click(TObject *Sender);
    private:        // User declarations
    public:         // User declarations
     __fastcall TForm1(TComponent* Owner);
    };
    extern PACKAGE TForm1 *Form1;
    #endif

    #include <vcl.h>
    #pragma hdrstop
    #include "Unit1.h"
    #pragna package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    __fastcall TForm1::TForm1(TComponent* Owner)
     : TForm(Owner)
    {
    }
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
      Form1->Color = clGreen;
      Caption = "ZelenΘ okno";
    }
    V uvedenΘ jednotce je pou╛ita t°φda a objekt. V na╣φ jednotce deklarujeme novou t°φdu TForm1, kterß je odvozena od t°φdy TForm. TForm1 je datov² typ a pro prßci v aplikaci pot°ebujeme prom∞nnou tohoto typu. Deklarujeme tedy instanci Form1 typu ukazatel na TForm1. Objekt Form1 reprezentuje samotn² formulß° (p°esn∞ji °eΦeno jednß se o ukazatel na formulß°). M∙╛eme deklarovat vφce ne╛ jeden objekt n∞jakΘ t°φdy. Nap°. m∙╛eme mφt vφce pod°φzen²ch oken v aplikacφ vφcedokumentovΘho rozhranφ.
    Na╣e aplikace obsahuje tlaΦφtko. T°φda TForm1 mß polo╛ku Button1, tj. p°idanΘ tlaΦφtko. TButton je t°φda a tedy Button1 je objekt. Poka╛dΘ, kdy╛ vlo╛φme novou komponentu na formulß°, je vlo╛ena do deklarace typu formulß°e novß polo╛ka se jmΘnem komponenty. V╣echny obsluhy udßlostφ jsou metody t°φdy formulß°e. Kdy╛ vytvo°φme novou obsluhu udßlosti, pak jejφ metoda je takΘ deklarovßna v typu formulß°e. TForm1 obsahuje metodu Button1Click. Aktußlnφ k≤d tΘto metody je uveden v souboru CPP. ProhlΘdn∞te si jednotku n∞kterΘ jinΘ aplikace a zjist∞te, kterΘ polo╛ky a metody jsou pou╛ity. Modifikßtor __fastcall urΦuje zp∙sob p°edßvßnφ parametr∙ u metod.
  3. Vytvß°enφ t°φdy v C++ Builderu zaΦφnßme odvozenφm t°φdy od existujφcφ t°φdy. Kdy╛ p°idßme do projektu nov² formulß°, pak C++ Builder jej automaticky odvozuje od TForm (je to definovßno prvnφm °ßdkem deklarace typu t°φdy, v na╣em p°φpad∞ class TForm1 : public TForm). V okam╛iku p°idßnφ formulß°e do projektu je novß t°φda identickß s typem TForm. Po p°idßnφ komponenty na formulß° nebo po zßpisu obsluhy udßlosti ji╛ identickß nenφ. Nov² formulß° je stßle pln∞ funkΦnφ formulß° (m∙╛eme m∞nit jeho velikost a umφst∞nφ a m∙╛eme jej takΘ uzav°φt). Novß t°φda formulß°e toti╛ zd∞dila v╣echny datovΘ polo╛ky, vlastnosti, metody a udßlosti od typu TForm. T°φda od kterΘ odvozujeme svoji t°φdu (od kterΘ d∞dφme data a k≤d) se naz²vß p°edek odvozenΘ t°φdy. Odvozenß t°φda je potomek svΘho p°edka. Prap°edek v╣ech t°φd je t°φda TObject.
  4. Rozsah platnosti urΦuje pou╛itelnost a p°φstupnost datov²ch polo╛ek, vlastnostφ a metod t°φdy; v╣echny jsou v rozsahu platnosti t°φdy a jsou pou╛itelnΘ t°φdou a jejφmi potomky. Kdy╛ zapisujeme k≤d do obsluhy udßlosti t°φdy, kter² se odkazuje na vlastnost, metodu nebo polo╛ku t°φdy samotnΘ, pak nemusφme uvßd∞t v odkazu jmΘno objektu. Nap°. p°φkaz v obsluze udßlosti pro Form1 Form1->Color = clGreen; lze napsat jako Color = clGreen;. Rozsah platnosti t°φdy je roz╣φ°en na v╣echny potomky t°φdy. M∙╛eme takΘ pou╛φt jmΘno metody ze t°φdy p°edka k deklaraci metody ve t°φd∞ potomka. Jednß se o p°edefinovßnφ metody (metoda potom ve t°φd∞ potomka bude provßd∞t n∞co jinΘho). Deklarace t°φdy obsahuje takΘ klφΦovß slova private: a public: oznaΦujφcφ mφsta pro datovΘ polo╛ky a metody, kterΘ chceme do k≤du zapisovat p°φmo. Ve°ejnou Φßst deklarace (Φßst za klφΦov²m slovem public) pou╛φvßme k deklarovßnφ datov²ch polo╛ek a metod, ke kter²m chceme p°istupovat z jin²ch jednotek. K deklaracφm v soukromΘ Φßsti (private) je omezen p°φstup pouze na tuto t°φdu.
  5. Nynφ se pokusφme vytvo°it vlastnφ t°φdu (jinou ne╛ t°φdu formulß°e) a to t°φdu umo╛≥ujφcφ pracovat s datumem. P°edpoklßdejme nßsledujφcφ deklaraci:

  6. class TDatum : public TObject {
      int Den, Mesic, Rok;
    public:
      TDatum(){};
      void NastavHodnotu(int D, int M, int R);
      bool Prestupny();
    };
    Na╣e t°φda se sklßdß ze t°φ polo╛ek: Den, Mesic a Rok, bezparametrickΘho konstruktoru (na╣i t°φdu odvozujeme od t°φdy, ve kterΘ je definovßn bezparametrick² konstruktor a v odvozenΘ t°φd∞ jej musφme tedy definovat takΘ) a dvou metod: NastavHodnotu a Prestupny. Funkce NastavHodnotu m∙╛e vypadat nap°. takto:
    void TDatum::NastavHodnotu(int D, int M, int R){
      Den = D;
      Mesic = M;
      Rok = R;
    }
    Nynφ ji╛ m∙╛eme deklarovat instanci t°φdy TDatum a s touto instancφ pracovat.
    TDatum  *Datum;
    Touto deklaracφ jsme nevytvo°ili objekt, ale pouze mφsto pro ulo╛enφ odkazu na objekt (ukazatel). Instance objektu vytvß°φme operßtorem new. Nßsleduje p°φklad prßce s na╣φ instancφ:
    Datum = new TDatum;
    Datum->NastavHodnotu(27, 5, 1942);
    ?
    Na╣φ t°φdu se pokusφme pou╛φt v n∞jakΘ aplikaci. Vytvo°φme formulß° se dv∞mi tlaΦφtky (p°i°adφme jim texty 1996 a 1997), kter²mi budeme urΦovat rok a budeme zji╣╗ovat, zda se jednß o p°estupn² rok. Vytvo°enφ objektu Datum budeme provßd∞t v obsluze udßlosti OnCreate formulß°e (vytvß°enφ formulß°e - tφm zajistφme, ╛e objekt je vytvo°en p°ed jeho pou╛itφm). Na zßv∞r (v obsluze udßlosti OnDestroy formulß°e) objekt op∞t zru╣φme. Nßsleduje v²pis obou programov²ch soubor∙ na╣eho formulß°e (hlaviΦkovΘho souboru a souboru CPP):
    #ifndef Unit1H
    #define Unit1H
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    class TDatum {
      int Den, Mesic, Rok;
    public:
      TDatum(){};
      void NastavHodnotu(int D, int M, int R);
      bool Prestupny();
    };
    class TForm1 : public TForm
    {
    __published:    // IDE-managed Components
     TButton *Button1;
     TButton *Button2;
     void __fastcall FormCreate(TObject *Sender);
     void __fastcall Button1Click(TObject *Sender);
     void __fastcall Button2Click(TObject *Sender);
    private:     // User declarations
    public:     // User declarations
     __fastcall TForm1(TComponent* Owner);
    };
    TDatum *Datum;
    extern PACKAGE TForm1 *Form1;
    #endif


    #include <vcl\vcl.h>
    #pragma hdrstop
    #include "Unit1.h"
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    TDatim *Datum;
    __fastcall TForm1::TForm1(TComponent* Owner)
     : TForm(Owner)
    {
    }
    void TDatum::NastavHodnotu(int D, int M, int R){
      Den = D;
      Mesic = M;
      Rok = R;
    }
    bool TDatum::Prestupny(){
      if (Rok % 4 != 0) return false;
      else if (Rok % 100 != 0) return true;
        else if (Rok % 400 != 0) return false;
          else return true;
    }
    void __fastcall TForm1::FormCreate(TObject *Sender)
    {
      Datum = new TDatum;
    }
    void __fastcall TForm1::FormDestroy(TObject *Sender)
    {
      delete Datum;
    }
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
      Datum->NastavHodnotu(1, 1, 1996);
      if (Datum->Prestupny()) Caption = "P°estupn²";
      else Caption = "Nep°estupn²";
    }
    void __fastcall TForm1::Button2Click(TObject *Sender)
    {
      Datum->NastavHodnotu(1, 1, 1997);
      if (Datum->Prestupny()) Caption = "P°estupn²";
      else Caption = "Nep°estupn²";
    }
    Prostudujte si tento v²pis a zjist∞te, co na╣e aplikace provßdφ. Vyzkou╣ejte.
  7. Pokuste se nynφ vynechat p°φkaz v obsluze udßlosti OnCreate formulß°e (objekt Datum nebudeme vytvß°et). Aplikaci znovu p°elo╛φme a teprve p°i stisku n∞kterΘho tlaΦφtka je signalizovßna chyba, kterß indikuje p°φstup k neplatnΘmu ukazateli. Vyzkou╣ejte.
  8. V na╣i t°φd∞ pou╛φvßme bezparametrick² konstruktor. Bylo by ale v²hodnΘ, aby nß╣ konstruktor zßrove≥ provedl inicializaci datov²ch polo╛ek t°φdy a to podobn∞ jako metoda NastavHodnotu. Vytvo°φme tento konstruktor a zm∞nφme takΘ obsluhu udßlosti OnCreate formulß°e. Bude nynφ tvo°ena p°φkazem:

  9. Datum = new TDatum(1, 1, 1900);
    Vyzkou╣ejte.
  10. Definici na╣φ t°φdy takΘ m∙╛eme umφstit do samostatnΘ jednotky a p°idßme novΘ metody. ZaΦneme s v²vojem novΘ aplikace, formulß° zatφm nechßme prßzdn² a zvolφme File | New Unit a dostaneme tento k≤d:

  11. #include <vcl.h>
    #pragma hdrstop
    #include "Unit2.h"
    #pragma package(smart_init)
    Jednotku p°ejmenujeme na Datumy a zapφ╣eme do nφ koneΦnou verzi definice t°φdy TDatum. Dostaneme tedy tyto dva soubory (H a CPP):
    #ifndef DatumyH
    #define DatumyH
    class TDatum {
    public:
      TDatum(int D, int M, int R);
      void NastavHodnotu(int D, int M, int R);
      bool Prestupny();
      void Zvetsi();
      void Zmensi();
      void Pricti(int PocetDni);
      void Odecti(int PocetDni);
      AnsiString ZiskejText();
    protected:
      int Den, Mesic, Rok;
      int DniVMesici();
    };
    #endif


    #include <vcl.h>
    #pragma hdrstop
    #include "Datumy.h"
    #pragma package(smart_init)
    TDatum::TDatum(int D, int M, int R){
      Den = D;
      Mesic = M;
      Rok = R;
    }
    void TDatum::NastavHodnotu(int D, int M, int R){
      Den = D;
      Mesic = M;
      Rok = R;
    }
    bool TDatum::Prestupny(){
      if (Rok % 4 != 0) return false;
      else
        if (Rok % 100 != 0) return true;
        else
          if (Rok % 400 != 0) return false;
          else return true;
    }
    int TDatum::DniVMesici(){
      switch (Mesic) {
        case 1:  case 3:  case 5:  case 7:  case 8:  case 10:
        case 12: return 31;
        case 4:  case 6:  case 9:
        case 11: return 30;
        case 2: if (Prestupny()) return 29;
                else return 28;
      };
    }
    void TDatum::Zvetsi(){
      if (Den < DniVMesici()) Den++;
      else if (Mesic < 12) { Mesic++; Den = 1; }
           else { Rok++; Mesic = 1; Den = 1; }
    }
    void TDatum::Zmensi(){
      if (Den > 1) Den--;
      else if (Mesic > 1) { Mesic--; Den = DniVMesici(); }
           else { Rok--; Mesic = 12; Den = DniVMesici(); }
    }
    void TDatum::Pricti(int PocetDni) {
      for (int N = 1; N <= PocetDni; N++) Zvetsi();
    }
    void TDatum::Odecti(int PocetDni) {
      for (int N = 1; N <= PocetDni; N++) Zmensi();
    }
    AnsiString TDatum::ZiskejText() {
      char pom[30];
      sprintf(pom, "%d.%d.%d", Den, Mesic, Rok);
      return AnsiString(pom);
    }
    Abychom tuto jednotku mohli vyzkou╣et vlo╛φme na ji╛ vytvo°en² formulß° komponentu Label (zv∞t╣φme velikost pφsma) a Φty°i tlaΦφtka (vybavφme je texty Dal╣φ, P°edchozφ, Za 10 a P°ed 10). Objekt t°φdy TDatum vlo╛φme jako soukromou polo╛ku do t°φdy formulß°e. Vytvo°φme obsluhy n∞kolika udßlostφ a dostaneme:
    #ifndef Unit1H
    #define Unit1H
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    class TForm1 : public TForm
    {
    __published:   // IDE-managed Components
     TLabel *Label1;
     TButton *Button1;
     TButton *Button2;
     TButton *Button3;
     TButton *Button4;
     void __fastcall FormCreate(TObject *Sender);
     void __fastcall Button1Click(TObject *Sender);
     void __fastcall Button2Click(TObject *Sender);
     void __fastcall Button3Click(TObject *Sender);
     void __fastcall Button4Click(TObject *Sender);
    private:    // User declarations
       TDatum *Datum;
    public:    // User declarations
     __fastcall TForm1(TComponent* Owner);
    };
    extern PACKAGE TForm1 *Form1;
    #endif


    #include <vcl.h>
    #pragma hdrstop
    #include "Datumy.h"
    #include "Unit1.h"
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    __fastcall TForm1::TForm1(TComponent* Owner)
     : TForm(Owner)
    {
    }
    void __fastcall TForm1::FormCreate(TObject *Sender)
    {
      Datum = new TDatum(14, 2, 1995);
      Label1->Caption = Datum->ZiskejText();
    }
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
      Datum->Zvetsi();
      Label1->Caption = Datum->ZiskejText();
    }
    void __fastcall TForm1::Button2Click(TObject *Sender)
    {
      Datum->Zmensi();
      Label1->Caption = Datum->ZiskejText();
    }
    void __fastcall TForm1::Button3Click(TObject *Sender)
    {
      Datum->Pricti(10);
      Label1->Caption = Datum->ZiskejText();
    }
    void __fastcall TForm1::Button4Click(TObject *Sender)
    {
      Datum->Odecti(10);
      Label1->Caption = Datum->ZiskejText();
    }
    void __fastcall TForm1::FormDestroy(TObject *Sender)
    {
      delete Datum;
    }
    Prostudujte si text tΘto aplikace a pokuste se pochopit jak pracuje. Aplikaci vyzkou╣ejte.
  12. Jako jednoduch² p°φklad d∞diΦnosti m∙╛eme pozm∞nit p°edchozφ aplikaci odvozenφm novΘ t°φdy a modifikovßnφm jednΘ z jeho funkcφ. M∞sφc v datumu budeme vypisovat slovn∞, a zm∞nφme tedy metodu ZiskejText. Vytvo°φme dal╣φ t°φdu (zapφ╣eme ji do jednotky Datumy):

  13. class TNoveDatum : public TDatum {
    public:
      TNoveDatum(int D, int M, int R): TDatum(D, M, R){};
      AnsiString ZiskejText();
    };
    Novß funkce ZiskejText pou╛φvß k v²pisu data konstantnφ pole s nßzvy m∞sφc∙:
    char JmenaMesicu[12][10] =
      {"leden", "·nor", "b°ezen", "duben", "kv∞ten", "Φerven",
       "Φervenec", "srpen", "zß°φ", "°φjen", "listopad", "prosinec"};
    AnsiString TNoveDatum::ZiskejText() {
      char pom[30];
      sprintf(pom, "%d. %s %d", Den, JmenaMesicu[Mesic-1], Rok);
      return AnsiString(pom);
    }
    V na╣φ aplikaci musφme je╣t∞ zm∞nit TDatum na TNoveDatum (v deklaraci formulß°e a v obsluze OnCreate) a aplikaci m∙╛eme vyzkou╣et.
  14. VCL je dob°e navr╛en² pracovnφ rßmec. Je zde v maximßlnφ mo╛nΘ mφ°e pou╛ita d∞diΦnost. Jßdrem VCL je t°φda reprezentujφcφ komponentu. Na nßsledujφcφm obrßzku je uvedena hierarchie t°φd VCL. Nenφ to ·plnΘ schΘma hierarchie, ale pouze nepatrnß Φßst. Na vrcholu nalezneme TObject. TObject je prap°edek v╣ech t°φd VCL. Pod TObject vidφme TPersistent. Tato t°φda dßvß komponentßm mo╛nost ulo╛it se do souboru a do pam∞ti a dal╣φ detaily nepot°ebujeme znßt.
  15. TComponent slou╛φ jako zßkladnφ t°φda pro komponenty. Tato t°φda poskytuje v╣echnu funkΦnost, kterou spoleΦn² zßklad komponent vy╛aduje. Nevizußlnφ komponenty jsou odvozeny p°φmo od TComponent. Vizußlnφ komponenty jsou odvozeny od t°φdy TControl, kterß je odvozena od TComtonent. TControl p°idßvß dal╣φ funkΦnost, kterou vy╛adujφ vizußlnφ komponenty. JednotlivΘ komponenty jsou pak odvozeny od TGraphicControl nebo TWinControl.
  16. T°φdy Form a Application reprezentujφ objekty formulß°∙ a aplikace ve VCL. Tyto t°φdy jsou odvozeny od TComponent a jsou tedy takΘ komponentami.

  17. T°φda TApplication zaobaluje zßkladnφ operace WindowsovskΘho programu. TApplication udr╛uje ikonu aplikace, poskytuje kontext nßpov∞dy a provßdφ zßkladnφ zpracovßnφ zprßv. Ka╛dß aplikace C++ Builderu mß ukazatel na objekt TApplication nazvan² Application. N∞kterΘ vlastnosti tohoto objektu m∙╛eme nastavovat na strßnce Application dialogovΘho okna Project Options (zobrazφ se volbou Project | Options). T°φda TForm zaobaluje ve VCL formulß°e. Formulß°e jsou pou╛ity jako r∙znß okna aplikace.
     
11. T°φdy v C++ Builderu I