10. Knihovna vizuálních komponent
  1. V roce 1995 Borland uvedl na trh nový produkt nazvaný Delphi. Delphi umožňuje rychlý vývoj aplikací pomocí něčeho, co se nazývá komponenta. Komponenty jsou objekty, které mohou být vloženy na formulář a pracujeme s nimi pomocí vlastností, metod a událostí. Je to vizuální programování.

  2. Delphi je založeno na jazyku Object Pascal a je v něm použita VCL (Visual Component Library). VCL je pracovní rámec aplikace pro programování ve Windows zapsaný v Object Pascalu. VCL není kompatibilní s OWL nebo MFC. Je to pracovní rámec, jehož jádro se velmi liší. VCL je založeno na koncepci vlastností, metod a událostí.
    Proč se zde ale zabýváme Delphi a jazykem Object Pascal? Důvod je jednoduchý. VCL které je jádrem Delphi je také jádrem C++ Builderu. I když komponenty VCL jsou zabaleny ve třídách Object Pascalu je možno je bez problémů používat v C++ Builderu.
    Veřejné rozhraní komponent (část komponent, kterou vidí uživatel) tvoří vlastnosti, metody a události. Vlastnosti jsou prvky komponent, které řídí práci komponenty. Mnoho komponent má společné vlastnosti. Všechny viditelné komponenty např. mají vlastnosti Top a Left. Tyto dvě vlastnosti určují pozici komponenty na formuláři a to jak během návrhu, tak i za běhu aplikace. Všechny komponenty mají vlastnost Owner, kterou VCL používá k uložení ukazatele na nadřízenou komponentu (nebo formulář), tj. vlastnost určuje vlastníka komponenty. Vlastnosti vybrané komponenty jsou zobrazovány v Inspektoru objektů a můžeme zde také měnit jejich hodnoty.
    Pokud např. změníme hodnotu vlastnosti Left samotného formuláře, pak formulář se na obrazovce přemístí podle zadané hodnoty této vlastnosti. To ukazuje důležitý aspekt vlastností; je to více než jednoduchá datová složka třídy. Každá vlastnost má přiřazenou datovou složku, ale samotná vlastnost není touto datovou složkou. Změna vlastnosti často způsobí provedení nějakého kódu, kterému říkáme přístupová metoda.
    Vlastnosti mohou být určeny během návrhu (když navrhujeme náš formulář) nebo za běhu aplikace (pomocí kódu běžícího programu). V obou případech, pokud vlastnost má přístupovou metodu, pak tato přístupová metoda je volána a provedena, když vlastnost je modifikována. Změníme-li vlastnost Left formuláře, pak přístupová metoda způsobí přesun formuláře na obrazovce.
    C++ Builder nám tedy umožní, abychom na obrazovce viděli výsledek naší změny. Ne všechny vlatnosti zobrazují provedené změny na formuláři během návrhu (někdy to není možné).
    Ke změně vlastnosti za běhu aplikace jednoduše vlastnosti přiřadíme hodnotu. Když provedeme přiřazení, pak VCL volá přístupovou metodu pro tuto vlastnost. Ke změně vlastnosti Left za běhu použijeme např. příkaz
    Form1->Left = 200;
    V případě vlastnosti Left (a také vlastnosti Top), VCL přesouvá a překresluje formulář (je provedeno voláním funkcí API Windows SetWindowPos a InvalidateRect). Povšimněte si, že v předchozím příkazu je použit k nastavení vlastnosti operátor nepřímého selektoru (->). Všechny komponenty VCL jsou alokovány v hromadě. Pro přístup k vlastnostem a metodám komponent je vždy používán nepřímý selektor. Třídy, které vytvoříme pro použití v aplikaci C++ Builderu můžeme alokovat v zásobníku nebo v hromadě, ale všechny třídy VCL komponent a všechny třídy od nich odvozené, musí být alokovány pouze v hromadě.
    Vlastnosti mají dva přístupové specifikátory, které jsou použity, když vlastnost je čtena nebo modifikována. Je to čtecí specifikátor a zápisový specifikátor. Je možno říci, že přístupové specifikátory přiřadí čtecí a zápisové metody k vlastnosti. Když vlastnost je čtena nebo zapisována, pak metody přiřazené k vlastnosti jsou volány automaticky. Když provedeme přiřazení (jako v předchozím příkazu), pak je zpřístupněn zápisový specifikátor. To způsobí, že VCL testuje, zda pro zápisový specifikátor existuje přístupová metoda. Pokud ano, pak je přístupová metoda volána. Pokud neexistuje, pak VCL přiřadí novou hodnotu datové složce přiřazené k vlastnosti.
    Když se odkazujeme na vlastnost (použijeme vlastnost na pravé straně přiřazovacího příkazu), pak je zpřístupněn čtecí specifikátor:
    int x = Form1->Left;
    V tomto případě VCL volá čtecí specifikátor pro přečtení hodnoty vlastnosti Left. Většinou čtecí specifikátor nedělá nic jiného než to, že vrací současnou hodnotu vlastnosti.
  3. Vlastnosti vlastností (promiňte toto spojení) jsou určeny tvůrcem komponenty. Některé vlastnosti mohou být určeny pouze pro čtení. Tyto vlastnosti můžeme číst (získat jejich hodnotu), ale nelze jejich hodnotu modifikovat. Mohou být také vlastnosti určené pouze pro zápis (není možno číst jejich hodnotu). Některé vlastnosti mohou být specifikovány pouze za běhu aplikace. Tyto vlastnosti nelze používat při návrhu a nejsou tedy zobrazovány v Inspektoru objektů. Vlastnosti obvykle mají implicitní hodnoty (počáteční hodnotu zobrazenou v Inspektoru objektů).

  4. Některé vlastnosti používají jako připojenou datovou složku pole. Je to např. vlastnost Lines komponenty Memo (pole textových řetězců). Když vybereme tuto vlastnost v Inspektoru objektů, pak na pravém okraji hodnoty vlastnosti vidíme malé tlačítko se třemi tečkami. Toto tlačítko nám říká, že vlastnost může být editována pomocí Editoru vlastností. Např. pro pole řetězců je zobrazeno dialogové okno, ve kterém můžeme editovat řetězce. V případě vlastnosti Font je při stisku tohoto tlačítka zobrazeno dialogové okno volby písma. Typ editoru vlastnosti závistí na typu vlastnosti a editor zobrazíme stiskem tlačítka se třemi tečkami nebo dvojitým kliknutím na hodnotě vlastnosti.
    Vlastnosti mohou být instance dalších tříd VCL. Příkladem je vlastnost Font. Tato vlastnost obsahuje informace jako typ písma, barvu a velikost písma, atd. Pokud najdeme vlastnost Font v Inspektoru objektů, pak vidíme před slovem Font znak plus. Tím jsme informováni o tom, že vlastnost se skládá z podvlastností. Dvojitým kliknutím na jménu vlastnosti s podvlastnostmi jsou v Inspektoru objektů tyto podvlastnosti zobrazeny a můžeme s nimi pracovat samostatně.
    Některé vlastnosti jsou množiny. Množina je kolekce možných hodnot pro vlastnost. Vlastnost Style v objektu Font je příkladem množiny. Povšimněte si, že u vlastnosti Style v Inspektoru objektů je uveden znak +. Pokud tuto vlastnost rozbalíme (dvojitě na ní klikneme), pak se zobrazí možné prvky množiny. V našem případě se jedná o styly písma: bold, italic, underline a strikeout. Množina může být prázdná nebo může obsahovat jednu nebo více možných hodnot. Dalším dvojitým kliknutím na stylu jej opět sbalíme.
    Výčet je seznam možných voleb pro vlastnost. Když je vybrána vlastnost s výčtem, pak na pravé straně její hodnoty je zobrazeno tlačítko rozbalovacího seznamu (stiskem tlačítka se seznam možných voleb rozbalí a můžeme z něj vybírat). Dvojitým kliknutím na hodnotě takovéto vlastnosti cyklicky procházíme seznamem voleb.
    Množina od výčtu se liší tím, že u výčtu musí být zvolena právě jedna z možných hodnot, zatímco u množiny jich může být libovolný počet.
  5. Metody v komponentách VCL jsou funkce, které mohou být volány k provedení jisté akce. Např. všechny vizuální komponenty mají metodu Show, která komponentu zobrazí a metodu Hide, která komponentu skryje. Např.

  6. MojeOkno->Show();
    // a později
    MojeOkno->Hide();
    Tyto funkce jsou normální metody třídy komponenty. Metody VCL mohou být stejně jako v C++ veřejné, soukromé nebo chráněné.
    Stejně jako funkce v C++, některé metody přebírají parametry a vracejí hodnoty. Závisí to na tom, jak metoda byla tvůrcem komponenty zapsána. Např. metoda GetTextBuf získává text z komponenty TEdit. Může být použita takto:
    char buff[256];
    int pocetZnaku = Edit1->GetTextBuf(buff, sizeof(buff));
    Jak vidíme, tato metoda přebírá dva parametry a vrací celočíselnou hodnotu. Když tuto metodu vyvoláme, pak obsah editační komponenty je umístěn do buff a vrácená hodnota je počet znaků získaných z editační komponenty.
  7. Windows je prostředí řízené událostmi. Událostmi řízené znamená, že program je řízen událostmi, které se vyskytnou v prostředí Windows. Události zahrnují přesun myši, kliknutí myší a stisk klávesy na klávesnici.

  8. Programátoři přecházející z prostředí DOSu nebo sálových počítačů mohou mít různé problémy s koncepcí událostmi řízeného programování. Programy pracující pod Windows stále získávají od Windows události. Události ve Windows zahrnují aktivování nabídky, stisknutí tlačítka, přesun okna, požadavek na překreslení okna, apod. Windows oznamuje událost programu zasíláním zpráv. V současnosti je asi 175 možných zpráv, které Windows může zaslat aplikaci, ale jen některé z nich se vyskytují častěji.
    Každá komponenta je určena k reagování na jisté události. Obvykle to jsou události Windows, ale mohou být i z jiného zdroje. Např. komponenta tlačítka je určena k reagování na kliknutí myší. Databázové komponenty mohou reagovat na události, které nepocházejí od Windows.
    Když komponenta reaguje na událost říkáme, že obsluhuje událost. Události jsou obslouženy pomocí funkcí nazvaných obsluhy událostí. Jména obsluh událostí pro komponentu jsou uvedeny na stránce Events Inspektora objektů. Jméno události popisuje událost, na kterou mají reagovat. Např. události kliknutí myší se nazývá OnClick.
  9. Po delší době se opět vrátíme k aplikacím GUI. Začneme vývoj nové aplikace. U formuláře změníme vlastnost Name na VMU (vlastnosti, metody a události) a Caption na Testovací program VMU. Dále přidáme na formulář komponentu Memo (zvětšíme ji na většinu plochy formuláře; při spodním okraji necháme místo pro tlačítko). U této komponenty změníme vlastnost Name na Memo a vlastnost Lines na text Testovací program používající vlastnosti, metody a události. Do spodní části formuláře vložíme ještě tlačítko. Změníme jeho vlastnost Name na Tlacitko, vlastnost Caption na Zobraz/Ukryj a vodorovně jej na formuláři vycentrujeme (pomocí palety zarovnávání; zobrazíme volbou View | Alignment Palette a zvolíme Center horizontally; centrovaný objekt musí být vybrán).

  10. Dále vytvoříme obsluhu stisku tlačítka. Je tvořena touto funkcí:
    void __fastcall TVMU::TlacitkoClick(TObject *Sender)
    {
      static bool jeViditelny;
      jeViditelny = !jeViditelny;
      if (jeViditelny) Memo->Hide();
      else Memo->Show();
    }
    Vidíme, že se jedná o metodu třídy TVMU (jméno našeho formuláře). Modifikátor __fastcall zde určuje způsob předávání parametrů při volání funkce. Kód obsluhy nastavuje hodnotu statické proměnné jeViditelny. Statická proměnná je taková proměnná, která neztrácí svoji hodnotu mezi funkčními voláními (je to něco jako globální proměnná). Statické proměnné jsou inicializovány nulou. V našem případě se jedná o proměnnou typu bool a je tedy inicializována hodnotou false. Vždy při volání této funkce proměnná jeViditelny obsahuje opačnou hodnotu než byla při předchozím volání. Program nyní můžeme vyzkoušet.
  11. Když se podíváme na naši statickou proměnnou, pak zjistíme, že pouze určuje, zda komponenta Memo je viditelná. Stejnou informaci obsahuje také vlastnost Visible komponenty Memo. Statická proměnná je tedy zbytečná a obsluhu stisku tlačítka lze změnit takto:

  12. void __fastcall TVMU::TlacitkoClick(TObject *Sender)
    {
      if (Memo->Visible) Memo->Hide();
      else Memo->Show();
    }
    Po provedení této změny se funkce programu nezmění.
  13. Naše obsluha události přebírá ukazatel na TObject nazvaný Sender. Každá obsluha události má alespoň tento parametr. Některé obsluhy událostí mají více parametrů. Podívejme se např. na obsluhu stisku tlačítka myši:

  14. void __fastcall TVMU::TlacitkoMouseDown(TObject *Sender,
         TMouseButton Button, TShiftState Shift, int X, int Y)
    {
    }
    Zde jsou parametry, které nás informují o tom, které tlačítko myši bylo stisknuto, které klávesy byly stisknuty a souřadnice místa stisknutí. Jsou to tedy informace, které můžeme potřebovat v obsluze události.
    Co to je ale Sender? Sender je ukazatel na komponentu, od které událost pochází. V našem programu parametr Sender je nepodstatný, protože již předem víme, že událost bude pocházet od našeho tlačítka Zobraz/Ukryj. Parametr Sender ale umožňuje, aby více komponent používalo jednu obsluhu události.
    Ukážeme si to na našem programu. Tlačítko již umístěné na formuláři přejmenujeme na Zobraz a přidáme další tlačítko Ukryj. Budeme postupovat takto: Pokud vrchním oknem je Editor kódu, pak stiskem tlačítka F12 jej přesuneme za návrhvý formulář. Vybereme již existující tlačítko a změníme u něj vlastnosti Name a Caption na Zobraz. Napravo od tohoto tlačítka přidáme nové tlačítko a změníme jeho Name a Caption na Ukryj.
    Když nyní vybereme tlačítko Zobraz a v Inspektoru objektů přejdeme na stránku Událostí, pak uvidíme, že obsluha události OnClick se nyní jmenuje ZobrazClick (přejmenovali jsme tlačítko). Vrátíme se k původnímu názvu, tj. zapíšeme zde TlacitkoClick. Vybereme dále tlačítko Ukryj, v Inspektoru objektů nalezneme událost OnClick a v rozbalovacím seznamu této události vybereme TlacitkoClick (v seznamu je uvedena pouze tato obsluha události). Na hodnotě TlacitkoClick v Inspektoru objektů dvojitě klikneme, čímž přejdeme do Editoru kódu na tuto obsluhu. Kód obsluhy modifikujeme takto:
    void __fastcall TVMU::TlacitkoClick(TObject *Sender)
    {
      if (Sender == Ukryj) Memo->Hide();
      else Memo->Show();
    }
    Program je hotov, můžeme jej vyzkoušet. Máme zde jednu obsluhu události, která obsluhuje událost OnClick obou tlačítek. Parametr Sender určuje, které tlačítko bylo stisknuto. Mohli bychom sice mít pro každé tlačítko jinou obsluhu události, ale není to nutné.
    V tomto příkladu jsme si ukázali, že po vytvoření obsluhy události pro jednu komponentu, můžeme připojit tuto obsluhu pro událost stejného typu jiné komponenty. Můžeme tedy použít stejnou obsluhu pro více komponent.
  15. Následuje několik rad pro používání událostí: Na každou událost komponenty můžeme reagovat podle potřeby. Není nutno reagovat na všechny události definované v komponentě. Události jsou obslouženy funkcemi nazvanými obsluhy událostí. Pro obsluhy událostí C++ Builder generuje implicitní jméno, které může být programátorem změněno. Jména obsluh událostí měníme pouze v Inspektoru objektů. Parametr Sender obsluhy události může být použit k zjištění, která komponenta událost generovala. Dvojitým kliknutím na jménu obsluhy události v Inspektoru objektů přejdeme do Editoru kódu na tuto obsluhu. Každá obsluha události obsahuje parametry potřebné k zpracování události.
  16. VCL je knihovna zapsaná v Object Pascalu. Je zapsána v Object Pascalu, protože byla původně určena pro Delphi. Nyní se používá i v C++ Builderu. C++ Builder je překladač C++ a v čem je vytvořeno VCL není podstatné. Podívejte se na následující kód:

  17. int sirkaObrazovky = GetSystemMetrics(SM_CXSCREEN);
    int vyskaObrazovky = GetSystemMetrics(SM_CYSCREEN);
    int v = MainForm->Height;
    int s = MainForm->Width;
    MainForm->Top = (vyskaObrazovky / 2) - (v / 2);
    MainForm->Left = (sirkaObrazovky / 2) - (s / 2);
    TPoint souradniceKurzoru;
    GetCursorPos(&souradniceKurzoru);
    v -= 150;
    s -= 150;
    MainForm->Height = v;
    MainForm->Width = s;
    for (int i = 0; i < 150; i +=3) {
      MainForm->Height = v + i;
      MainForm->Width = s + i;
      SetCursorPos(MainForm->Left + MainForm->Width,
                   MainForm->Top + MainForm->Height);
    }
    SetCursorPos(souradniceKurzoru.x, souradniceKurzoru.y);
    Můžeme jej např. používat jako obsluhu stisku tlačítka. Položme si otázku co v tomto kódu je Object Pascal a co C++. Vše je C++. VCL i C++ mohou pracovat současně, což umožňuje rychlý vývoj aplikací pomocí C++. VCL dává rychlý vývoj pomocí komponent a zbytek může být zapsán v C++. Je potřeba pouze dodržovat některá pravidla.
  18. Když vložíme komponentu na formulář C++ Builder automaticky zapisuje kód, který dynamicky vytváří komponentu (a nemusíme ani vědět jak). Musíme to ale znát, když chceme vytvořit a používat třídu VCL za běhu programu. Např. můžeme potřebovat zobrazit dialogové okno otevření souboru a nemáme komponentu TOpenDialog vloženou na formulář. Není to žádný problém, můžeme objekt vytvořit sami. Provedeme to takto:

  19. TOpenDialog *dlg = new TOpenDialog(this);
    dlg->Title = "Otevření nového souboru";
    dlg->Execute();
    Objekt musí být vytvořen pomocí operátoru new. Všechny pokusy o lokální alokaci jsou odmítnuty. Většinu komponent VCL můžeme vytvářet za běhu, stejně jako v průběhu návrhu. Je snadnější vytvářet komponenty při návrhu, neboť k nastavování vlastností lze použít Inspektor objektů (není nutno je nastavovat prostřednictvím kódu). Podívejme se ale na následující kód:
    TRect obdelnik;
    obdelnik.top = 0;
    obdelnik.left = 0;
    obdelnik.right = 100;
    obdelnik.bottom = 100;
    Zde není dodržen požadavek na dynamickou alokaci. To je možno proto, že TRect není třída, TRect je struktura, která zaobaluje strukturu RECT Windows. Jinak řečeno TRect VCL je jiné jméno pro strukturu RECT Windows. Stejně to platí i pro TPoint, TSize, TLogFont, TDrawItemStruct a další struktury Windows, které jsou dostupné pro použití ve VCL.
  20. VCL neumožňuje použití implicitních parametrů funkcí. Ukážeme si to na funkci MessageBox Windows API. Tato funkce přebírá čtyři parametry: madlo okna zobrazujícího okno zpráv, text zprávy, titulek okna a parametr Flags určující tlačítka a ikony zobrazené v okně zpráv. V MFC nebo OWL lze použít tuto funkci pouze se specifikací zobrazeného textu:

  21. MessageBox("Toto je zpráva");
    Toto je možné v OWL nebo MFC (lze zde využít implicitní hodnoty parametrů) ale ne ve VCL. Ve VCL je nutno použít:
    Application->MessageBox("Toto je zpráva", "Zpráva", MB_OK);
    Zde je nutno specifikovat všechny parametry. Povšimněte si, že ve všech třech případech (OWL, MFC i VCL) je pracovním rámcem automaticky vytvořen parametr madla okna.
  22. Třídy VCL nepodporují vícenásobnou dědičnost. Tzn. nelze vytvořit novou komponentu odvozením od dvou existujících komponent. Není to velké omezení, neboť vícenásobná dědičnost je používána velmi zřídka a nelze ji používat pouze ve spojitosti s VCL. Ve třídách, které nejsou obvozeny od VCL ji v C++ Builderu můžeme i nadále používat bez omezení.
  23. Je nutno se také seznámit s třídami řetězců znaků VCL. V konzolových aplikacích jsme používali řetězce jako pole znaků. Nyní již víme, že jazyk C++ umožňuje vytvořit třídu k provádění požadovaných úloh. Je ale dobrá a špatná zpráva. Dobrou zprávou je, že existuje třída usnadňující práci s řetězci. Špatná zpráva je, že takovýchto tříd je několik. Nejprve se podívejme na C způsob:

  24. char buff[30];
    strcpy(buff, "Ahoj!");
    if (!strcmp(buff, "Ahoj!"))
      strcat(buff, " Co je nového?");
    Toto při používání tříd řetězců je možno zapsat takto:
    String S = "Ahoj!";            // přímé přiřazení
    if (S == "Ahoj!")              // test na rovnost
      S = S + " Co je nového?";    // zřetězení řetězců
    Pokud porovnáme tyto dva kódy, pak můžeme říci, že druhý je mnohem srozumitelnější. Vidíme, že můžeme provádět přiřazení řetězce pomocí operátoru =, rovnost testujeme operátorem == a k přidání řetězce na konec jiného řetězce používáme operátor +.
    Třídy řetězců také mají metody. Tyto metody umožňují zjistit délku řetězce, hledat v řetězci podřetězce, zrušit část řetězce, převádět řetězce na velká písmena a mnoho dalších.
    Jak je uvedeno výše, máme možnost volit z více tříd řetězců. Jednou z těchto tříd řetězců, která je částí knihovny tříd C++ je třída string. Druhou nalezneme v STL (knihovna standardních šablon). Jedná se o třídu basic_string. Obě jsou dobrými třídami řetězců, ale nejsou určeny pro práci s VCL. VCL nabízí další dvě třídy řetězců.
  25. Třída SmallString emuluje datový typ krátkého řetězce Pascalu (Pascal má dva datové typy řetězců: krátké a dlouhé řetězce). Třída SmallString je implementována jako šablona. Tato třída je poskytnuta z důvodu kompatibility s Pascalem a nepoužíváme ji při zápisu nového kódu v C++ Builderu. Při používání této třídy používáme syntaxi:

  26. SmallString<30> s;
    s = "Nazdar";
    Jediným důvodem pro používání této třídy v aplikcích C++ Builderu je to, že ji vyžadují některé komponenty.
  27. Základním datovým typem řetězců ve VCL je Pascalovský dlouhý řetězec. Je to datový typ všech textových vlastností komponent. Např. vlastnosti Text, Name a Caption jsou všechno dlouhé řetězce Pascalu. VCL také používá tento typ v mnoha metodách a obsluhách událostí komponent.

  28. V Pascalu je dlouhý řetězec datovým typem jazyka a ne pole znaků jako v C nebo C++. V C++ neexistuje jeho zabudovaný ekvivalent. Protože dlouhé řetězce jsou používány hlavně ve VCL a protože C++ Builder používá Pascalovské VCL, je vytvořena třída, která odpovídá tomuto typu Pascalu. Tato třída se jmenuje AnsiString a může být použita vždy, když je vyžadován Pascalovský dlouhý řetězec.
    Někde v hlavičkovém souboru SYSDEFS.H nalezneme následující řádek:
    typedef AnsiString String;
    To umožňuje použití jména String (s velkým S) při deklaraci instance třídy AnsiString namísto použití oficiálního jména třídy AnsiString.
    String s = "Toto je test";
    Protože String je doporučovaná přezdívka pro třídu AnsiString, není důvod k používání jména AnsiString v našich programech C++ Builderu (i když jej samozřejmě můžeme používat).
    AnsiString je třída řetězců s velkými možnostmi. Konstruktory této třídy umožňují vytvořit objekt AnsiString z char, char *, int a double. Tyto konstruktory usnadňují přiřazení řetězcové konstanty AnsiString a převod celého nebo reálného čísla na řetězec. Všechny následující příklady používají konstruktory AnsiString (některé explicitně a jiné implicitně):
    String FloatString = 123.45;
    String JinyFloatString(0.999);
    String IntString = 49;
    String CharString = 'A';
    Label1->Caption = "Toto je test";
    double d = 3.14 * 20;
    Edit1->Text = d;
    V případě přímého přiřazení, překladač C++ aplikuje příslušný konstruktor. Pro první příkaz je tedy provedeno něco jako:
    String FloatString = String((double)123.45);
    Jiným důvodem, že předchozí kód pracuje je to, že třída AnsiString má přetížen operátor přiřazení (=). Další přetížené operátory, které zjednoduššují práci jsou operátor zřetězení (+) a operátor rovnosti (==).
    Třída AnsiString má mnoho metod, které usnadňují manipulaci s řetězci. V následující tabulce jsou uvedeny často používané metody. Není to úplný seznam metod (popis všech metod nalezneme v nápovědě).
     
    Metoda Popis
    c_str Vrací ukazatel (char *) na text řetězce.
    Delete Ruší část řetězce.
    Insert Vkládá text do specifikovaného řetězce na specifikovanou pozici.
    Length Vrací délku řetězce (bez ukončujícího NULL).
    LowerCase Převádí řetězec na malá písmena.
    Pos Vrací pozici hledaného řetězce v řetězci.
    SubString Vrací podřetězec z řetězce, začínající na dané pozici a dané délky.
    ToDouble Převádí řetězec na číslo v pohyblivé řádové čárce. Pokud řetězec nemůže být převeden, je generována výjimka.
    ToInt Převádí řetězec na celé číslo. Pokud řetězec nemůže být převeden, je generována výjimka.
    ToIntDef Převádí řetězec na celé číslo a určuje implicitní hodnotu pro případ, kdy řetězec nemůže být převeden.
    Trim Odstraňuje úvodní a koncové mezery z řetězce.
    UpperCase Převádí řetězec na velká písmena.
    Některé z těchto metod potřebují vysvětlení. Jednou z nich je metoda c_str. Tato podivně nazvaná metoda je potřebná, když požadujeme získat ukazatel na znakovou oblast AnsiString (ukazatel na pole znaků). To vyžadují některé funkce API. Např. funkci API DrawText používáme takto:
    RECT R(0, 0, 100, 20);
    // nejprve způsob C
    char buff[] = "Toto je test";
    DrawText(Canvas->Handle, buff, -1, &R, DT_SINGLELINE);
    // nyní způsob VCL
    String s = "Toto je test";
    DrawText(Canvas->Handle, s.c_str(), -1, &R, DT_SINGLELINE);
    Druhý parametr funkce DrawText vyžaduje ukazatel na řetězec zobrazovaných znaků a získáme jej metodou c_str.
    Dále se zastavíme u metody ToInt. Tato metoda převádí textový řetězec na celočíselnou hodnotu. Např. na formuláři máme editační komponentu, kterou budeme používat k získání celočíselné hodnoty od uživatele. Protože editační komponenta drží pouze text, musíme jej převést na celé číslo. To provedeme takto:
    int hodnota = Edit1->Text.ToInt();
    Podobně pracuje metoda ToDouble. Pokud převod nemůže být proveden, pak obě metody generují výjimku. Např. když uživatel zadá S123, pak je generována výjimka, protože S nelze převést na celé číslo.
    Některé metody nepracují na řetězci samotném, ale vracejí nový řetězec. Je to např. metoda UpperCase. Pokud použijeme následující kód, pak zjistíme, že se nic nestane:
    String JmenoSouboru = "c:\\prac\\mojedata.dat";
    JmenoSouboru.UpperCase();
    Správné použití je:
    JmenoSouboru = JmenoSouboru.UpperCase();
    Ještě se zmíníme o metodě Format, která umožňuje vytvářet řetězce z proměnných a to stejně jako to umožňuje funkce sprintf. Při našem seznamování s touto funkcí jsme uvedli příkazy:
    char buff[20];
    int x = 10 * 20;
    sprintf(buff, "Výsledek je: %d", x);
    Stejný výsledek dosáhneme i při použití metody Format:
    String S;
    int x = 10 * 20;
    S = Format("Výsledek je: %d", OPENARRAY(TVarRec, (x)));
    Je několik důvodů, aby metoda byla zapsána tímto způsobem, ale nebudeme se jimi nyní zabývat. Můžeme říci, že metodu Format nebudeme používat a to proto, že si nebudeme pamatovat jak ji použít. Její použití lze také snadno obejít. Např.
    int x = 10 * 20;
    char buff[20];
    sprintf(buff, "Výsledek je: %d", x);
    String S = buff;
    U třídy AnsiString se lze také odkazovat na jednotlivé znaky řetězce. Používáme k tomu operátor indexace ([]). Např.
    String S = "Ahoj";
    Label1->Caption = S[2];
    Tento kód přiřadí vlastnosti Caption komponenty Label1 znak h (znaky řetězce jsou indexovány od 1; tj. první znak řetězce má index 1). To je vyžadováno pro kompatibilitu s Delphi. Může to být zdrojem některých chyb. Např. následující kód programu je chybný.
    String S = "c:\\prac\\mujprogram.exe";
    int index = S.LastDelimiter("\\");
    S.Delete(0, index);
    Tento kód je chybný neboť 0 není přípustným indexem. Správný zápis posledního řádku je:
    S.Delete(1, index);
  29. Vytvoříme nyní aplikaci s formulářem, na který vložíme editační ovladač, dvě komponenty Label (jednu nad editační ovladač a druhý pod) a tlačítko. Editační ovladač vyprázdníme, u horní komponenty Label změníme Caption na Zadej text:, u spodní komponenty Label vlastnost Caption vyprázdníme a u tlačítka změníme text na Změň na velká písmena. Pro tlačítko vytvořte potřebnou obsluhu události OnClick (text z editační komponenty převedeme na velká písmena a zobrazíme jej ve spodní komponentě Label).
  30. Vytvořte aplikaci, ve které budete zjišťovat existenci zadaného podřetězce v zadaném řetězci (můžete použít metodu Pos třídy AnsiString). Řetězec a podřetězec zadávejte v editačních ovladačích. Vypisujte, zda podřetězec byl nebo nebyl nalezen.
  31. Vytvořte aplikaci, která zadaný text v editačním ovladači upraví takto: Mezi jednotlivé znaky původního řetězce budou vloženy znaky mezer. Výsledek zobrazte v komponentě Label.
  32. Jazyk Pascal má datový typ množina, který opět není v C++. Množiny jsou ve VCL často používané a musíme znát jak je použít. Množina je kolekce podobných objektů. Např. vlastnost Style třídy TFont může obsahovat nula nebo více následujících hodnot: fsBold, fsItalic, fsUnderline a fsStrikeout.

  33. Jak již bylo uvedeno výše, v jazyku C++ není zabudovaná podpora množin. V C++ se pro podobné účely používají bitová pole, což je vyhovující způsob. My ale potřebujeme používat způsob z VCL a proto C++ Builder emuluje množiny Pascalu. Je to provedeno šablonou třídy nazvanou Set. Tato šablona se velmi snadno používá.
    Vraťme se k vlastnosti Style. Tuto vlastnost někdy potřebujeme nastavit i za běhu aplikace. Např. chceme přidat atributy pro tučné písmo a kurzívu. Můžeme deklarovat proměnnou typu TFontStyles (typ množiny možných stylů písma) a k této množině přidat styly fsBold a fsItalic. To provedeme takto:
    TFontStyles Styly;
    Styly << fsBold << fsItalic;
    Povšimněte si použití operátoru <<. Tento operátor je ve třídě Set přetížen k umožnění přidávání prvku do množiny. Výše uvedený kód nezmění styl písma, pouze vytvoří množinu a vloží do ní dva prvky. Ke změně stylu písma, musíme přiřadit nově vytvořenou množinu vlastnosti Font->Style nějaké komponenty:
    Memo1->Font->Style = Styly;
    Později můžeme požadovat, aby písmo zůstalo tučné, ale aby již nebyla použita kurzíva. V tomto případě můžeme odstranit styl kurzívy z množiny. K odstranění prvku z množiny používáme operátor >>:
    Styly >> fsItalic;
    Memo1->Font->Style = Styly;
    Často potřebujeme zjistit, zda v množině se vyskytuje nějaký prvek. Např. chceme zjistit, zda styl písma je nastaven na tučné písmo. K tomu lze použít metodu Contains:
    bool jeTucne = Memo1->Font->Style.Contains(fsBold);
    if (jeTucne) delejNeco();
    Někdy potřebujeme začínat prázdnou množinou. K vyprázdnění množiny používáme metodu Clear. Např.
    Memo1->Font->Style.Clear();
    Memo1->Font->Style = Memo1->Font->Style << fsBold << fsItalic;
    Zde nejprve množinu vyprázdníme a pak přiřadíme dva styly. Můžeme ale také vytvořit dočasnou množinu (množina po vytvoření je vždy prázdná) a ihned do ní přidat dva prvky. Předchozí kód je možno také zapsat takto:
    Memo1->Font->Style = TFontStyle() << fsBold << fsItalic;
    Následující kód je ale chybný:
    Memo1->Font->Style << fsBold << fsItalic;
    Zde nemůže být volána zápisová metoda vlastnosti Style. K provedení aktualizace vlastnosti Style je nutno používat operátor přiřazení:
    Memo1->Font->Style = Memo1->Font->Style << fsBold << fsItalic;

Kontrolní otázky:

  1. Co to je pracovní rámec?
  2. Je VCL pracovní rámec C++?
  3. Je zapotřebí umět programovat v Pascalu a v C++ při programování v C++ Builderu?
  4. Jsou vlastnosti datovými složkami tříd?
  5. Musíme reagovat na všechny události definované komponentou?
  6. Jsou všechny komponenty viditelné během návrhu?
  7. Mohou být objekty VCL alokovány lokálně (v zásobníku) nebo dynamicky?
  8. Jsou metody v komponentách VCL ekvivalentní s funkcemi v C++?
  9. Jsou všechny třídy VCL odvozeny od TObject?
  10. Uveďte některou nevizuální komponentu?
  11. Sdílejí všechny komponenty některé společné vlastnosti?
  12. Uveďte alespoň dvě vlastnosti, které mají všechny vizuální komponenty.
  13. Může několik komponent sdílet stejnou obsluhu události?
Řešení
10. Knihovna vizuálních komponent