13. Třídy v C++ Builderu III
  1. Dokončete vytváření vaší kalkulačky.


  2. Prapředkem všech tříd VCL je třída TObject. Podívejme se na její definici.

  3. class DELPHICLASS TObject {
    public:
      __fastcall  TObject();
      __fastcall Free();
      TClass  __fastcall ClassType();
      void    __fastcall CleanupInstance();
      void *  __fastcall FieldAddress(const ShortString &Name);
      static TObject * __fastcall InitInstance(TClass cls, void *instance);
      static ShortString __fastcall ClassName(TClass cls);
      static bool __fastcall ClassNameIs(TClass cls, const AnsiString string);
      static TClass __fastcall ClassParent(TClass cls);
      static void * __fastcall ClassInfo(TClass cls);
      static long __fastcall InstanceSize(TClass cls);
      static bool __fastcall InheritsFrom(TClass cls, TClass aClass);
      static void * __fastcall MethodAddress(TClass cls, const ShortString &Name);
      static ShortString __fastcall MethodName(TClass cls, void *Address);
      bool __fastcall GetInterface(const TGUID &IID, /* out */ void *Obj);
      static PInterfaceEntry __fastcall GetInterfaceEntry(const TGUID IID);
      static PInterfaceTable * __fastcall GetInterfaceTable(void);
      ShortString __fastcall ClassName() {return ClassName(ClassType()); }
      bool __fastcall ClassNameIs(const AnsiString string)
        { return ClassNameIs(ClassType(), string); }
      TClass __fastcall ClassParent() { return ClassParent(ClassType()); }
      void * __fastcall ClassInfo() { return ClassInfo(ClassType()); }
      long __fastcall InstanceSize() { return InstanceSize(ClassType()); }
      bool __fastcall InheritsFrom(TClass aClass)
        { return InheritsFrom(ClassType(), aClass); }
      void * __fastcall MethodAddress(const ShortString &Name)
        { return MethodAddress(ClassType(), Name); }
      ShortString __fastcall MethodName(void *Address)
        { return MethodName(ClassType(), Address); }
      virtual HResult __fastcall SafeCallException(TObject *ExceptObject,
                                                   void *ExceptAddr);
      virtual void __fastcall AfterConstruction();
      virtual void __fastcall BeforeDestruction();
      virtual void __fastcall Dispatch(void *Message);
      virtual void __fastcall DefaultHandler(void* Message);
    private:
      virtual TObject* __fastcall NewInstance(TClass cls);
    public:
      virtual void __fastcall FreeInstance();
      virtual __fastcall ~TObject();
    };
    V tomto výpisu je deklarována třída TObject, která obsahuje několik metod, které můžeme aplikovat na jakýkoli objekt VCL, včetně námi definovaných objektů odvozených od TObject. Většina metod třídy TObject je často používána systémem. Některé metody třídy TObject mohou hrát důležitou roli při psaní obecných aplikací. Např. metoda ClassName vrací řetězec se jménem třídy. Tuto metodu je možné aplikovat jak na objekt (instanci), tak i na třídu (datový typ), protože se jedná o statickou metodu. Někdy může být také užitečné získat odkaz na vlastní třídu nebo jejího předchůdce. To zajišťují metody ClassType a ClassParent. Jakmile známe odkaz na třídu, můžeme jej použít stejným způsobem, jako by se jednalo o objekt: např. pro volání metody ClassName. Další užitečná metoda je InstanceSize, která vrací velikost objektu. Použití některých metod této třídy si ukážeme v následující aplikaci. Metodu ClassNameIs jsme již použili v předchozí kapitole při tažení typu písma. Na formulář umístíme okno seznamu (ListBox) a tlačítko. Obsluha stisknutí tlačítka bude tvořena následujícími příkazy (povšimněte si také posledního příkazu, který zabrání dalšímu stisknutí tlačítka):
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
      ListBox1->Items->Add("Jméno třídy: " + Button1->ClassName());
      ListBox1->Items->Add("Jméno třídy předka: " +
        Button1->ClassParent()->ClassName());
      ListBox1->Items->Add("Velikost instance: " +
        IntToStr(Button1->InstanceSize()));
      ListBox1->Items->Add(" ");
      ListBox1->Items->Add("Jméno třídy: " + ClassName());
      ListBox1->Items->Add("Jméno třídy předka: " +
        ClassParent()->ClassName());
      ListBox1->Items->Add("Velikost instance: " + IntToStr(InstanceSize()));
      Button1->Enabled = false;
    }
    Vyzkoušejte činnost aplikace a pokuste se pochopit jak pracuje (a co dělá).
  4. Hlavní nabídka C++ Builderu obsahuje všechny volby potřebné k práci s C++ Builderem. Tato nabídka se používá obvyklým způsobem. Nejčastěji používané volby je možno také zadávat na Paletě nástrojů. Paleta nástrojů je popsána na následujícím obrázku.


  5. Paleta nástrojů je plně přizpůsobitelná. Mezi Paletou nástrojů a Paletou komponent je svislá čára, kterou je možno přetahovat myší vlevo nebo vpravo a měnit tak šířku těchto palet. Přizpůsobování Palety nástrojů je snadné. Na paletu můžeme přidávat tlačítka, odstraňovat tlačítka a měnit uspořádání tlačítek. Pro konfiguraci Palety nástrojů musíme použít místní nabídku. Ukážeme myší na Paletu nástrojů a k zobrazení místní nabídky klikneme pravým tlačítkem myši. Volby místní nabídky jsou popsány v následující tabulce.
     
    Prvek nabídky Popis
    Show Hints Určuje zda je zobrazována bublinková nápověda pro tlačítka palety.
    Hide Skrývá Paletu nástrojů.
    Help Vyvovává nápovědu C++ Builderu pro Paletu nástrojů.
    Properties Zobrazí dialogové okno Editoru palety nástrojů, které umožňuje Paletu nástrojů přizpůsobit podle našich požadavků.
    Pokud Paletu nástrojů skryjeme, pak její opětovné zobrazení lze provést volbou View | Toolbar.
    Pro přizpůsobování Palety nástrojů musíme v místní nabídce palety zvolit Properties. Tím zobrazíme dialogové okno Editoru palety nástrojů. Toto dialogové okno obsahuje všechna možná tlačítka palety. Pro přidání tlačítka na paletu stačí tlačítko pouze přetáhnout myší z okna Editoru na paletu. K odstranění tlačítka z palety, stačí tlačítko přetáhnou mimo paletu. Uspořádání tlačítek na paletě lze provést jejich přetažením na nové pozice. Tlačítko Reset v okně Editoru slouží pro návrat k implicitnímu nastavení tlačítek.
  6. Paleta komponent C++ Builderu je používána k výběru komponenty, kterou budeme umisťovat na formulář. Paleta komponent je vícestránkové okno. Záložky stránek umožňují přecházet mezi stránkami. Umístění komponenty na formulář je dvoukrokový proces. Nejprve pomocí Palety komponent vybereme komponentu, kterou chceme umístit na formulář a potom kliknutím na formuláři umístíme komponentu na formulář. Levý horní roh komponenty je umístěn na místě kliknutí.

  7. Někdy se dostaneme do situace, že potřebujeme na formulář umístit více stejných komponent. K provedení této akce stiskneme a při výběru komponenty na Paletě komponent držíme stisknutou klávesu Shift. Po výběru komponenty klávesu uvolníme. Vybrané tlačítko komponenty je nyní na paletě zobrazeno s modrým rámečkem. Nyní při každém kliknutí na formuláři umístíme na formulář vždy tuto vybranou komponentu. Komponenta zůstává stále vybrána. K zrušení jejího výběru stikneme na Paletě komponent výběrové tlačítko (tlačítko se šipkou na levé straně palety).
    Komponenty na formulář lze vkládat ještě jiným způsobem. Jednoduše dvojitě klikneme na tlačítko komponenty na paletě nástrojů a komponenta je umítěna doprostřed formuláře. Komponentu potom můžeme běžným způsobem přetáhnout na požadované místo.
    Paleta komponent má stejnou místní nabídku jako Paleta nástrojů. Používáme ji stejným způsobem k provádění obdobných úloh.
    Na Paletě komponent nemusí být zobrazeny všechny existující záložky stránek (nevejdou se tam) a zobrazená stránka nemusí zobrazovat všechny komponenty, které jsou na ní umístěny. V těchto případech lze použít posuvníky podle následujícího obrázku.
  8. Nedílnou součástí IDE C++ Builderu je Inspektor objektů. Inspektor objektů umožňuje nastavovat vlastnosti komponent během návrhu. Inspektor objektů má tři hlavní oblasti:
  9. Selektor komponenty je rozbalovací seznam v horní části Inspektora objektů. Selektor komponenty umožňuje výběr komponenty. Obvykle komponentu vybíráme kliknutím myši na komponentě na formuláři. Někdy to ale není možné (komponenta může být překryta jinou komponentou).
    Selektor komponenty zobrazuje třídu komponenty a třídu od které je komponenta odvozena. Např. komponenta Memo nazvaná Memo je uvedena v Selektoru objektů takto:
    Memo: TMemo
    Jméno třídy se nezobrazuje v rozbalovacím seznamu komponent, ale pouze v horní části Selektoru komponent. Výběr komponenty provedeme výběrem v Selektoru komponenty. V Selektoru komponenty jsou uvedeny pouze komponenty z aktuálního formuláře a samotný formulář. Ostatní formuláře a jejich komponenty zde nejsou uváděny.
    Stránka vlastností Inspektora objektů zobrazuje všechny vlastnosti dostupné během návrhu pro právě vybranou komponentu. Stránka vlastností má dva sloupce. Vlevo je sloupec se jmény vlastností a vpravo sloupec hodnot. Pokud na formuláři je vybráno více komponent, pak Inspektor objektů uvádí všechny vlastnosti, které mají vybrané komponenty společné. Toto můžeme využít při modifikaci několika komponent najednou. Např. ke změně šířky několika komponent na stejnou hodnotu vybereme všechny tyto komponenty a v Inspektoru objektů změníme hodnotu vlastnosti Width. Vlastnost Width je tím modifikována u všech vybraných komponent.
    V mnoha případech je při zadávání testována přípustnost hodnoty vlastnosti. Např. hodnota vlastnosti Width nemůže být záporná. Zadáme-li zde zápornou hodnotu, pak ji C++ Builder změní na nejmenší možnou hodnotu (obvykle na 0). Zadáme-li zde hodnotu, která není celým číslem, pak je vypsána chybová zpráva.
    Stránka událostí uvádí všechny události, které komponenta může zpracovávat. K vytvoření obsluhy události, dvojitě klikneme ve sloupci hodnot u události, kterou chceme obsloužit. V tomto případě jméno obsluhy události je generováno C++ Builderem. Jestliže obsluze události chceme jméno přiřadit sami, pak jej zapíšeme do sloupce hodnot a stiskneme Enter.
    C++ Builder odstraňuje všechny prázdné obsluhy událostí při překladu nebo ukládání jednotky do souboru. To využíváme v případě, kdy potřebujeme některou vytvořenou obsluhu událost zrušit. Pouze vyprázdníme její obsah a při příštím překladu je takováto obsluha odstraněna. Není vhodné při rušení obsluhy postupovat tak, že v Editoru kódu vymažeme celou obsluhu (včetně hlavičky). Pokud zrušení provedeme tímto způsobem, pak při překladu je signalizována chyba (C++ Builder neví, že obsluha byla zrušena).
  10. C++ Builder je určen k vytváření aplikací založených na VCL. Můžeme jej ale použít k vytvoření jiného typu aplikace? C++ Builder je standardní překladač C++ a lze jím tedy překládat libovolný typ 32 bitového programu C++. Běžně je možno použít C++ Builder k vytváření DLL (dynamicky sestavovaná knihovna). Při seznamování s C++ jsme si mnohokrát ukázali, že v C++ Builderu lze vytvářet konzolové aplikace. Můžeme také překládat programy zapsané v MFC nebo OWL. V tomto případě použijeme samostatný překladač.

  11. Nyní si ukážeme jak vytvořit program, který používá pouze funkce API. Jedná se o program, který vytvoří okno a do okna vypíše nějaký text. Začněme vytvářet novou aplikaci, postupujeme, jako při vytváření konzolové aplikace a v průvodci vytvářením konzolové aplikace nastavíme volič Windows (GUI). Vygenerovaný obsah zdrojového souboru smažeme a nahradíme jej následujícím kódem.
    #define STRICT
    #include <windows.h>
    #pragma hdrstop
    #pragma argsused
    LRESULT FAR PASCAL _export WndProc(HWND, UINT, WPARAM, LPARAM);
    int PASCAL WinMain(HINSTANCE hInstance,
      HINSTANCE hPrevInstance, LPSTR lpszCmd, int nCmdShow)
    {
      static char AppName[] = "HelloWorld";
      HWND        hwnd;
      MSG         msg;
      WNDCLASS    wndclass;
      if (!hPrevInstance)
      {
        wndclass.style         = CS_HREDRAW | CS_VREDRAW;
        wndclass.lpfnWndProc   = (WNDPROC)WndProc;
        wndclass.cbClsExtra    = 0;
        wndclass.cbWndExtra    = 0;
        wndclass.hInstance     = hInstance;
        wndclass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
        wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
        wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        wndclass.lpszMenuName  = 0;
        wndclass.lpszClassName = AppName;
        RegisterClass(&wndclass);
      }
      hwnd = CreateWindow(AppName,
        "Hello World",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        NULL,
        NULL,
        hInstance,
        NULL);
      ShowWindow(hwnd, SW_NORMAL);
      while (GetMessage(&msg, NULL, 0, 0))
      {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
      return msg.wParam;
    }
    LRESULT FAR PASCAL _export
    WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
      switch(message)
      {
        case WM_PAINT :
        {
          char text[] = "Ahoj!";
          PAINTSTRUCT ps;
          BeginPaint(hwnd, &ps);
          TextOut(ps.hdc, 20, 20, text, 5);
          EndPaint(hwnd, &ps);
          break;
        }
        case WM_DESTROY : {
          PostQuitMessage(0);
          return 0;
        }
        default:
          return DefWindowProc(hwnd, message, wParam, lParam);
      }
      return 0;
    }
    Program přeložíme a spustíme. Vidíme, že v C++ Builderu je možno vytvořit program API Windows. Toto je pouze ukázka možností C++ Builderu. Takovéto programy nebudeme vytvářet.
13. Třídy v C++ Builderu III