18. Nabídka II
  1. Někdy se můžeme dostat do situace, kdy všechny ovladače se nevejdou na plochu formuláře. Jestliže komponenty rozmístíme na velký formulář a potom zmenšíme jeho velikost (tak, že některé komponenty se do něj již nevejdou), jsou do formuláře automaticky přidány posuvníky. Toto nyní vyzkoušíme. V nové aplikaci uděláme široký formulář, po celé jeho ploše rozmístíme různé komponenty a formulář zúžíme. Aplikaci spustíme a vyzkoušíme.

  2. Do této aplikace se dále pokusíme přidat malé stavové okno, které nás bude informovat o stavu vodorovného posuvníku. K aplikaci tedy přidáme další formulář. Přidáme na něj (pod sebe) dvě komponenty Label s texty ?Šíře formuláře:? ?Pozice posuvníku:? a vedle nich další dvě komponenty Label pro výpis aktuálních hodnot. Velikost tohoto formuláře zmenšíme a nastavíme jeho vlastnosti takto: Caption na Stav posuvníku, BorderIcons na [biSystemMenu], BorderStyle na bsSingle, FormStyle na fsStayOnTop a Visible na true (po spuštění aplikace bude formulář viditelný). Pro hlavní formulář vytvoříme ještě obsluhu události OnResize s příkazy:
    Form2->Label3->Caption = IntToStr(ClientWidth);
    Form2->Label4->Caption = IntToStr(HorzScrollBar->Position);
    Aplikaci spustíme a při změně velikosti formuláře se mění zobrazované hodnoty ve stavovém okně. Když ale použijeme posuvník, pak hodnoty ve stavovém okně se nezmění. Builder toto neumožňuje neboť pro formulář neexistuje událost OnScroll (není to nutné, neboť ve většině případů formuláře obsluhují posuvníky automaticky). Tato událost by byla zapotřebí pouze v některých speciálních případech (např. právě v naši aplikaci).
  3. Velkou výhodou C++ Builderu je to, že když velikost některé komponenty na formuláři se změní, pak se podle potřeby automaticky přidají nebo odstraní posuvníky. Jako příklad můžeme použít komponentu Image. Jestliže do komponenty nahrajeme nový obrázek a její vlastnost AutoSize je nastavena na true, pak komponenta automaticky mění velikost podle velikosti obrázku a formulář přidává nebo odstraňuje posuvníky. Vraťme se k naši aplikaci zobrazovače obrázků. Jedná se o formulář zobrazující bitovou mapu nahranou ze souboru, která je zobrazena v původní velikosti nebo deformována tak, aby se do formuláře vtěsnala. U našeho původního zobrazovače obrázků (v předchozí kapitole) změníme u komponenty Image vlastnost AutoSize na true, z nabídky odstraníme volbu Centrovat a změníme obsluhu volby Zaplnit (při zapnuté volbě odstraníme posuvníky) takto:

  4. Image1->Stretch = ! Image1->Stretch;
    Centrovat1->Checked = Image1->Stretch;
    if (Image1.Stretch) Image1->Align = alClient;
    else {
      Image1->Align = alNone;
      Image1->Height = Image1->Picture->Height;
      Image1->Width = Image1->Picture->Width;
    }
    Aplikace je hotova. Zmenšíme formulář a nahrajeme nějaký velký obrázek. Vidíme, že jsou v případě potřeby automaticky přidány posuvníky.
  5. Vytvořte aplikaci, kde na formuláři bude pouze editační ovladač. K formuláři vytvořte místní nabídku, která umožní měnit barvu formuláře (použijte zde volby Modrá, Červená a Zelená) a pro editační ovladač vytvořte jinou místní nabídku (s volbami Písmo a Velikost písmen - druhou volbou měňte vlastnost CharCase editačního ovladače). Aplikaci vyzkoušejte.
  6. Při zobrazování místní nabídky barvy formuláře by bylo vhodné, aby prvek nabídky určující současnou barvu formuláře byl odškrtnutý. Pokusíme se tuto změnu provést. Využijeme toho, že při zobrazování místní nabídky vzniká událost OnPopup. Vytvoříme tedy obsluhu této události:

  7. for (int I = 0; I < PopupMenu1->Items->Count; I++)
      PopupMenu1->Items->Items[I]->Checked = false;
    if (Color == clBlue) Modr1->Checked = true;
    if (Color == clRed) erven1->Checked = true;
    if (Color == clGreen) Zelen1->Checked = true;
    Na počátku obsluhy je u všech prvků místní nabídky zrušeno odškrtnutí pomocí cyklu na poli Items místní nabídky. Cyklus probíhá od 0 do Count-1. Jeho výhodou je to, že funguje na všech prvcích nabídky, nezávisle na jejich počtu. Vyzkoušejte.
  8. Zatím jsme používali automatické místní nabídky. Alternativou je nastavení vlastnosti AutoPopup na false a použití metody Popup pro zobrazení místní nabídky na obrazovku. Metoda vyžaduje dva parametry, X a Y souřadnice plánovaného umístění nabídky. Problém je v tom, že musíme zadat souřadnice bodu obrazovky a ne uživatelské souřadnice, které se u uživatelské plochy obvykle používají.

  9. Začneme novou aplikaci, kde na formulář umístíme pouze komponentu Memo, která zaplní celý formulář. Do komponenty Memo zapíšeme několik řádků textu. Pro komponentu vytvoříme dvě místní nabídky. První bude umožňovat změnu písma a barvy komponenty (prvky Písmo a Barva) a druhá bude určovat zarovnávání textu v komponentě (prvky Vlevo, Vpravo a Doprostřed). U obou nabídek nastavíme vlastnost AutoPopup na false. Budeme se snažit, aby vždy při stisku pravého tlačítka myši se nabídka změnila. Vytvoříme tedy obsluhu stisku tlačítka myši (OnMouseDown) pro komponentu Memo:
    if (Button == mbRight) {
      TPoint KlBod, ObBod;
      KlBod.x  = X;
      KlBod.y = Y;
      ObBod = ClientToScreen(KlBod);
      PocetKliknuti++;
      if (PocetKliknuti & 1) PopupMenu1->Popup(ObBod.x, ObBod.y);
      else PopupMenu2->Popup(ObBod.x, ObBod.y);
    }
    V obsluze je nejprve zjištěno, zda bylo stisknuto pravé tlačítko myši, dále jsou uživatelské souřadnice místa kliknutí převedeny na obrazovkové souřadnice (pomocí metody ClientToScreen), počítán počet kliknutí (deklarujeme PocetKliknuti jako soukromou položku formuláře; je typu int) a zobrazíme příslušnou nabídku. Obsluhy voleb nabídky vytvořte sami. U druhé nabídky se pokuste odškrtnout aktuálně nastavenou volbu.
  10. V další aplikaci se seznámíme s používáním komponenty MaskEdit. Jedná se o editační komponentu, která má speciální vlastnost EditMask. Jestliže otevřeme Editor vstupní masky (stiskem tlačítka (...) v Inspektoru objektů), můžeme snadno definovat řetězec vstupní masky, který určuje zapisovaný řetězec. Mimo zadání masky umožňuje Editor vstupní masky zadat znak použitý pro určení místa pro vstup a rozhodnout, zda se budou s řetězcem ukládat i další znaky obsažené v masce. Např. u kódu země v telefonním čísle si můžeme závorky nastavit pouze jako vstupní pomůcku nebo je ukládat i s řetězcem telefonního čísla. Tyto dva údaje odpovídají poslední části masky (implicitní oddělovač je středník). Stiskneme-li v Editoru vstupní masky tlačítko Masks, pak můžeme otevřít soubor masek. Předdefinované soubory obsahují standardní masky pro některé země.

  11. Začneme s vývojem nové aplikace. Na formulář umístíme komponentu MaskEdit a v Editoru vstupní masky vybereme některou masku. Před tuto komponentu umístíme text Editace s maskou:. Pod MaskEdit umístíme komponentu Edit a před ní text Editační maska:. Do spodní části formuláře umístíme komponentu ListBox obsahující popis znaků masky. Zadáme zde tyto řetězce znaků (komponentu zvětšíme):
    (l) možné písmeno (letter)
    (L) vyžadované písmeno
    (a) možný alfanumerický znak
    (A) vyžadovaný alfanumerický znak
    (c) možný znak (character)
    (C) vyžadovaný znak
    (9) možná číslice
    (0) vyžadovaná číslice
    (#) číslice nebo znaménko
    (_) mezera (můžeme měnit znak reprezentující mezeru)
    (\) následující znak je interpretován jako literál
    (>) převod na velká písmena
    (<) převod na malá písmena
    (<>) bez úpravy velikosti písmen
    (!) potlačení úvodních mezer
    (/) standardní systémový oddělovač měsíců, dnů a roků v datumu
    (:) standardní systémový oddělovač hodin, minut a sekund v čase
    (;) oddělovač polí masky
    Vytvoříme ještě dvě obsluhy událostí. Obsluha události OnCreate formuláře bude tvořena příkazem:
    Edit1->Text = MaskEdit1->EditMask;
    a obsluha OnChange editačního ovladače příkazem:
    MaskEdit1->EditMask = Edit1->Text;
    Nyní již aplikaci můžeme vyzkoušet. Do editačního ovladače zadáme nějakou masku a vyzkoušíme jaký má vliv na vstup v komponentě MaskEdit.
  12. Dále budeme pokračovat v našem obecném seznamování s komponentami. Zaměříme se nyní na tlačítka. VCL obsahuje několik typů tlačítek, která můžeme používat ve svých aplikacích. Ne všechny jsou založeny na standardních ovladačích Windows. Nejprve se budeme zabývat tlačítkem Button. Tento typ tlačítka má pouze 4 zajímavé vlastnosti. Vlastnost ModalResult je použita k zabudovanému uzavření formuláře, který byl zobrazen pomocí ShowModal. Implicitně ModalResult je nastavena na mrNone (hodnotu 0). Při použití této hodnoty se tlačítko chová jako normální tlačítko (neuzavírá formulář). Jesliže pro ModalResult použijeme jinou hodnotu, pak stisknutí tlačítka uzavírá formulář a vrací hodnotu ModalResult. Následuje seznam předdefinovaných konstant ModalResult ve VCL: mrNone, mrOK, mrCancel, mrAbort, mrRetry, mrIgnore, mrYes, mrNo, mrAll, mrNoToAll a mrYesToAll.

  13. Vlastnost Default je další klíčovou vlastností tlačítek. Windows má standardní mechanismus pro práci s dialogovými okny. Jedna ze služeb tohoto mechanismu je: Pokud zaostření má jiný ovladač než některé tlačítko a uživatel stiskne klávesu Enter, pak dialogové okno se chová stejně jako kdyby uživatel stiskl implicitní tlačítko. Implicitní tlačítko je tlačítko, které má nastavenu vlastnost Default na true. Podobně pracuje vlastnost Cancel. Namísto klávesy Enter se ale týká klávesy Esc. Pokud u více tlačítek je hodnota vlastnosti Default nebo Cancel nastavena na true, pak je použito první tlačítko v Tab pořadí, které je nalezeno. Vlastnost Enabled pracuje obdobně jako u jiných komponent. Pokud u některého tlačítka nastavíme vlastnost Enabled na false, pak tlačítko je nefunkční (je zakázáno).
    Implicitní hodnota vlastnosti Height je 25 a implicitní hodnota vlastnosti Width je 75. Tlačítko obvykle umisťujeme na formulář a reagujeme na jeho událost OnClick.
    Komponenta BitBtn je ukázkou toho, jak komponenta může být rozšířena k poskytnutí další funkčnosti. V tomto případě stantardní komponenta Button je rožířena k umožnění zobrazování bitové mapy na tlačítku. Komponenta BitBtn má o několik vlastností více než komponenta Button. Všechny tyto přidané vlatnosti se týkají obrázku na tlačítku. Vlastnost Glyph určuje bitovou mapu zobrazovanou na tlačítku (obrázek obvykle ve formátu BMP). Obrázek samotný obsahuje jednu nebo více bitových map, které reprezentují až 4 možné stavy tlačítka. Standardní obrázky tlačítek poskytnutých s C++ Builderem mají rozměry 15 x 15 a zachycují dva stavy. Vlastnost Kind je služba komponenty BitBtn, která umožňuje volit z několika předdefinovaných tlačítek. Implicitní hodnota pro vlastnost Kind je bkCustom, která znamená, že obrázek a další vlastnosti tlačítka budeme nastavovat sami. Volbou jiné hodnoty se nastaví automaticky tyto další vlastnosti: Glyph, Cancel nebo Default, Caption a ModalResult. Vlastnost Layout určuje, zda obrázek bude zobrazen před, za, nad  nebo pod textem. Implicitní hodnota je blGlyphLeft. Vlastnost Margin určuje mezeru mezi obrázkem a okrajem tlačítka. Implicitní hodnota je -1, což znamená, centrování obrázku a textu v tlačítku. Vlastnost NumGlyphs určuje počet obrázků (počet stavů tlačítka). Vlastnost Spacing určuje velikost mezery mezi obrázkem a textem v bodech.
    Komponenta SpeedButton je určena k používání s panelem k vytváření palet nástrojů. Od předchozích dvou typů tlačítek se liší tím, že se nejedná o Windowsovský ovladač, tzn. nemůže získaz zaostření. Na druhé straně SpeedButton má několik věcí společných s BitBtn (např. Glyph). Tyto tlačítka jsou implicitně čtverce o rozměrech 25 x 25 (můžeme změnit na libovolnou velikost) a mohou obsahovat text (text se ale obvykle nepoužívá). V C++ Builderu 1.0 se k vytváření palety nástrojů používala komponenta Panel. C++ Builder 3.0 má pro tyto účely komponentu Toolbar (jsou zde předdefinované další možnosti).
    Tlačítka SpeedButton můžeme seskupovat do skupin. Když jedno tlačítko ve skupině stiskneme, pak zůstane stisknuté a dříve stisknuté tlačítko je uvolněno (pouze jedno může zůstat stisknuto). Skupinu tlačítek vytvoříme přiřazením stejné hodnoty jejich vlastnostem GroupIndex (implicitní hodnota 0 indikuje, že tlačítko nepatří do žádné skupiny). Přiřazením nenulové hodnoty vlastnosti GroupIndex se změní chování tlačítka.
    Implicitně ve skupině může být stisknuté pouze jedno tlačítko. Toto chování lze změnit nastavením vlastnosti AllowAllUp na true. Tím dosáhneme toho, že stisknuto může zůstat více tlačítek. Někdy požadujeme, aby komponenta SpeedButton pracovala jako přepínací tlačítko (indikace zapnutí nebo vypnutí nějaké volby). Toho dosáhneme vytvořením skupiny s jedním tlačítkem, kde AllowAllUp je nastaveno na true. Čtením vlastnosti Down lze zjistit, zda tlačítko je stisknuto (true). Zápisem do této vlastnosti měníme stav (stisknutí) tlačítka (má vliv pouze na tlačítka ve skupině).
  14. Značky a voliče lze také považovat za tlačítka. Komponenty RadioButton a CheckBox mají vlastnost Checked, kterou lze použít k nastavení stavu nebo k získání současného stavu. Voliče jsou obvykle používány ve skupině (skupina voleb, z nichž pouze jedna může být vybrána). Pokud na formuláři potřebujeme více skupin voličů, pak je vhodné každou skupinu vytvořit jednou komponentou RadioGroup. Tato komponenta usnadňuje vytvoření skupiny voličů a také poskytuje jejich orámování a titulky (jak pro voliče - vlastnost Items; zadáváme v Editoru řetězců - tak i pro celou skupinu). Komponenta RadioGroup má vlastnost ItemIndex, která určuje označený volič.

  15. Skupinu voličů je také možno vytvořit umístěním několika komponent RadioButton na komponentu GroupBox (na GroupBox je možno umístit i jiné komponenty). Pokud používáme pouze voliče, pak je výhodnější použít RadioGroup.
    Komponenta CheckBox je používána k umožnění uživateli zapínat a vypínat nějakou volbu a indikovat zda volba je právě zapnuta nebo vypnuta. Značky mohou mít až 3 stavy (zapnuto, vypnuto a neurčeno). Pokud vlastnost AllowGrayed je nastavena na false (implicitně), pak k určení stavu značky používáme vlastnost Checked. Jestliže ale vlastnost AllowGrayed má hodnotru true, pak k testování (nebo nastavení) stavu značky je nutno použít vlastnost State (možné hodnoty cbChecked, cbUnchecked a cbGrayed). Pokud potřebujeme značku použít pouze k indikaci nějakého stavu a neumožnit měnit uživateli stav značky (značku určenou pouze pro čtení) a nechceme aby značka byla šedá, pak ji můžeme umístit na panel s vlastností Enabled nastavenou na false.
  16. Komponenta Label je používána k zobrazení textu na formuláři. Text může být statický (neměnný) nebo dynamický (za běhu aplikace se může měnit). Ke změně textu se používá vlastnost Caption. Komponenta Label nemá žádné specializované metody nebo události. Důležité vlastnosti jsou popsány v následující tabulce:

  17.  
    Vlastnost Popis
    AutoSize Při nastavení na true, mění komponenta svoji velikost podle textu obsaženého ve vlastnosti Caption. Při nastavení na false, je text oříznut pravým okrajem ovladače.
    FocusControl Label je neWindowsovská komponenta a nemůže tedy získat zaostření. Může ale sloužit jako text pro jiný ovladač (např. Edit). V těchto případech můžeme přiřadit ovladači urychlovací klávesu (pomocí &) a vlastností FocusControl přiřadit ovladač, který při použití urychlovací klávesy má být zaostřen.
    ShowAccelChar Při nastavení na true, jsou znaky & zobrazovány v textu (neslouží k označení urychlovací klávesy).
    Transparent Při nastavení na true, je ignorována vlastnost Color (barva pozadí je vždy zobrazována průhlednou barvou). To je užitečné při umisťování komponenty Label na pozadí tvořené např. bitovou mapou.
    WordWrap Při nastavení na true, text komponenty je při dosažení pravého okraje zalamován (pokračuje na novém řádku).
  18. Komponenta ScrollBar reprezentuje samostatný posuvník (není součástí jiné komponenty). Aplikace mohou využívat posuvníky k nastavování nějakých hodnot. Posuvník je určen nastavením vlastností: Min, Max, LargeChange a SmallChange. Pozici madla posuvníku můžeme nastavit nebo zjistit prostřednictvím vlastnosti Position. Vlastnost Kind určuje, zda se jedná o vodorovný nebo svislý posuvník.
  19. Windows také poskytuje několik dialogových oken. Komponenty zaobalující tato okna nalezneme na stránce Dialogs Palety komponent. K zobrazení těchto dialogových oken používáme metodu Execute. Dialogová okna zobrazujeme modálně (s výjimkou Find a Replace, které jsou zobrazovány nemodálně). Execute vrací true, pokud uživatel stiskl tlačítko OK, dvojitě klikl na jménu souboru (v případě souborových dialogových oken) nebo stiskl klávesu Enter. Execute vrátí false, pokud uživatel stiskl tlačítko Cancel, klávesu Esc nebo uzavřel dialogové okno tlačítkem na titulním řádku okna. Část příkazu:

  20. if (OpenDialog->Execute()) {
    je ekvivalentní s:
    if (OpenDialog->Execute() == true) {
    Dialogová okna otevření a uložení souboru si popíšeme podrobněji. Dialogové okno otevření souboru použijeme, když chceme uživateli umožnit ve své aplikaci otevírání souboru. Je zaobaleno v komponentě OpenDialog. Dialogové okno uložení souboru je použito, když získáváme jméno ukládaného souboru od uživatele. Je zaobaleno v komponentě SaveDialog. Obě komponenty mají několik zajímavých vlastností.
    Vlastnost DefaultExt použijeme k nastavení implicitní přípony, kterou dialogové okno bude používat. Tato přípona bude automaticky připojena ke jménu souboru, v případě kdy uživatel příponu nezadá. Vlastnost FileName je nejdůležitější vlastností. Obsahuje text jména souboru, který uživatel zvolil. Tuto vlastnost také nastavujeme před voláním dialogového okna, pokud jméno souboru chceme zobrazit v okně při jeho zobrazování. Files je vlastnost určená pouze pro čtení, obsahující seznam vybraných souborů, když je povolen vícenásobný výběr.
    Vlastnost Filter obsahuje seznam typů souborů, ze kterých uživatel může vybírat. Tyto typy jsou zobrazovány v kombinovaném ovladači Files of type. Dvojitým kliknutím na hodnotě vlastnosti Filter v Inspektoru objektů zobrazíme Editor filtrů, kde ve sloupci Filter Name zadáváme textový popis typu souboru a ve sloupci Filter souborovou masku, která bude použita k odfiltrování jmen souborů tohoto typu. Vlastnost FilterIndex je použita k nastavení filtru, který je použit při zobrazení dialogového okna (filtry jsou číslovány od 1).
    Vlastnost InitialDir je používána ke specifikace adresáře, který bude použit při zobrazování dialogového okna. Pokud hodnota této vlastnosti není zadána, pak aktuální adresář je určen Windows. Vlastnost Options určuje způsob použití dialogového okna. Seznam možných voleb je příliš dlouhý a jsou zde volby určující možnost vytváření nových adresářů, zobrazení tlačítka Help v okně, zda mohou být používána dlouhá jména, zda je povolen vícenásobný výběr a řada dalších. Vlastnost Title je používána k nastavení nebo čtení titulku dialogového okna.
  21. Existují další dvě komponenty, které rozšiřují funkčnost OpenDialog a SaveDialog (zobrazují právě vybraný obrázek) - slouží pro otevírání a ukládání souborů obrázků. Mají také nastavenu vlastnost Filter na formáty obrázků Windows.

  22. Dialogové okno Color umožňuje volbu barvy. Vybraná barva je určena vlastností Color. Dialogové okno Font umožňuje volbu písma ze seznamu dostupných písem systému. Vlastností Device volíme, zda chceme v okně zobrazovat obrazovková písma, písma tiskárny nebo obojí. Velikost písma lze omezit vlastnosmi MaxFontSize a MinFontSize. Vlastnost Options obsahuje řadu voleb, které lze použít k ovlivňování funkčnosti okna. Vlastnost Font obsahuje všechny informace o vybraném písmu. Dialogové okno volby písma má jednu událost, událost OnApply, která nastane, když uživatel stiskne tlačítko Apply. Tlačítko Apply je zobrazeno v okně po vytvoření obsluhy události OnApply.
  23. Dialogová okna Find a Replace umožňují uživateli zadávat hledaný text (nahrazovaný text) a řadu různých voleb hledání a nahrazování. Tato okna jsou ve VCL reprezentována komponentami FindDialog a ReplaceDialog. Hlavní vlastnosti těchto komponent zahrnují FindText (hledaný text), ReplaceText (text, který nahradí nalezený text; obvykle není ve FindDialog) a Options (řada různých voleb). Tato okna se používají jiným způsobem než ostatní okna (jsou zobrazeny jako modální). S jejich použitím se seznámíme později.

Kontrolní otázky:

  1. Pokud změníme vlastnost Name komponenty pomocí Inspektora objektů, jsou automaticky také změněny všechny odkazy na tuto komponentu v kódu?
  2. Komponenta OpenDialog je obvykle viditelná. Proč ji řadíme mezi nevizuální komponenty?
  3. Proč je možné vlastnost Name měnit pouze v Inspektoru objektů?
  4. Proč nelze použít instanci třídy TStrings pro uložení seznamu řetězců v našem programu (překladač nepovolí vytvořit instanci TStrings)?
  5. Je možno měnit vlastnost Name komponent za běhu aplikace?
  6. Kterou vlastnost používáme k zakázání (povolení) komponenty?
  7. Která komponenta je často používána jako kontejner dalších komponent?
Řešení
18. Nabídka II