Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!
Zadejte Vaši e-mailovou adresu:
Kamarád fotí rád?
Přihlas ho k odběru fotomagazínu!
Zadejte e-mailovou adresu kamaráda:
C/C++
Jak vyzrát na GUI 3.díl - Tlačítka, menu, atd.
GUI
23. září 2002, 00.00 | Pokračování seriálu o programování grafického uživatelského rozhraní. Dnes nás čeká naprogramování základního objektu GUI - tlačítka a další, neméně důležité věci.
{Objekt C_BUTTON}Po delší (opravdu delší) pauze jsem opět zde s dalším dílem seriálu Jak vyzrát na GUI. Všem, kteří jste četli mé předchozí články a netrpělivě jste čekali na další díl se velmi omlouvám za zpoždění. Ale teď už k věci. Pokud se nepletu, v minulém díle jsem vám slíbil, že se dnes budeme zabývat tlačítky, meny, atd. V tuto chvíli již máme představu o podobě skriptu GUI a nadefinovali jsme si základní objekt C_GUI. Nemáme ovšem nadefinováný ostatní objekty jako C_BUTTON, C_LABEL, C_MENU a přístupové funkce.
Objekt C_BUTTONTento objekt bude asi pro spoustu programátorů důležitý. Bez ostatních jako např. obrázek, popisek se obejdeme, ale já si myslím, že pokud chcete něco odkliknout (hlášku napíšete snadno), je to bez tlačítka dosti obtížné :-) Začněme tedy tímto objektem a hned jeho definicí. Jako každý objekt našeho GUI bude odvozen od předka C_GUI_OBJECT. Jeho definici naleznete v předchozím článku.
|
V podstatě se nám budou těla fci.(pouze s menšími změnami) opakovat i u ostatních objektu. Aby jsme si zjednodušili práci s kreslením rámečků (v podstatě jsou u každého objetu), nadefinujeme si jednoduchou fci., které řekneme kam má rámeček vykreslit a jakou má mít barvu. Jelikož toto GUI není vyhrazeno pouze pro OpenGL, ale i pro ostatní knihovny, bude k přepsání vykreslovací fce. stačit úprava fce. kreslící rámečky a vypisující text. To značně ulehčí přepisování a zvětší přehlednost, oproti způsobu, kde by každý objekt obsahoval vlastní kus kódu zabývající se vykreslováním.
|
Pokud budeme chtít vykreslit například modrou plochu o rozměrech
100x100 na pozici [20,20] se žlutým rámečkem, budeme postupovat asi
takto :
|
Tak toto by byl nutný zaklad, ale stále nám schází jednotlivé metody.
Mohli by jsme začít například funckí / metodou pro vykreslování C_BUTTON::Draw()
Pokud si vzpomínáte na minulý článek, na konci jsme probírali
barevná schémata nastavovaná ve skriptu, pro každé menu zvlášť. Pro
nás teď budou podstatné barvy, které začínají na #line_ (#line_color,
#line_move_color, #line_down_color), stejné je to u #button_ a #text_.
Co vlastně znamenají jednotlivé přípony?
color - | standartní barva, která se používá při vykreslování |
move_color - | barva, která se použije při pohybu myší nad objektem (highlight efekt) |
down_color - | barva při stisku levého myšítka nad objektem |
Toto schéma se bude stále opakovat i u ostatních objektů, ale pojďme se již podívat na samotnou vykreslovací fci.
|
No, asi jste si všimli, že je tu dost neznámých věcí. Vezmeme to hezky po pořádku. O třídě C_MENU jsem se zmínil v minulém článku, její definici si uvedeme níže. Takže zatím, prosím, nezoufejte, vše bude vysvětleno. Někdo by se mohl pozastavit nad aktivováním texturování (glEnable(GL_TEXTURE_2D);) bez předešlého "nabindování" textury (glBindTexture();). Toto se děje při zavolání metody objekty C_GUI::Draw(); (celkové vykreslení GUI). My totiž předpokládáme, že se textura v průběhu vykreslování GUI nezmění. A co funkce OutTextXY();? Pokud si vzpomínáte na funkce OutText(); a MoveText(); Nebudete mít s touto funkcí problémy. Jsou to totiž ony dvě funkce v jedné, s tím rozdílem, že se automaticky neodřádkovává text. A kde jsme vzali proměnnou mouse_state? Ta se naplní ve funkci C_BUTTON::Test();
|
To je testovací funkce. Ostatní budou v podstatě podobné, až na menší změny. Poslední funkcí z tohoto objektu, kterou jsem ještě nezmínil je C_BUTTON::Exec_Command(); Tato funkce pouze spustí příslušnou funkci přiřazenou ve skriptu. Jedinou věcí, na kterou by jsme si měli dát pozor je : Tato funkce se volá až po otestování a vykreslení všech objektů a před vymazáním ukazatele na aktivní / vybraný objekt (focus). Umístíme ji tedy do fce. C_GUI::Draw(); Ale to až dál.
|
A jak vypadá praxe? První obrázek je tlačítko v klidu, na druhém je zvýrazněné a na třetím je při stisknutém levém myšítku. Grafická úprava a vykreslení je pak už na každém. Pokud chce někdo obrázek na pozadí, stačí upravit fci. Draw_Rect(). :-)
[-more-]{Mateřský objekt C_MENU}
Mateřský objekt C_MENU
O tomto objektu jsem
se zmiňoval již vícekrát a konečně je zde. Na začátek
musím říci, že to opravdu nebude žádná věda, protože nám
poslouží jako jakýsi prostor pro informace. Jedinou věcí, proč ho
vlastně potřebujeme je roztřídění jednotlivých tlačítek
do menu a určení barev platných pro každé menu zvlášť. A to je v
podstatě vše. Teď už je vám jasné, že to žádna věda není,
definice objektu vypadá takto :
|
Pokud jste pozorně četli minulý článek, bude vám jasné,
proč se i tento objekt odvozuje od C_GUI_OBJECT. Pokud ne, tak vám
to vysvětlím. Ve třídě C_GUI je obsaženo pole ukazatelů
na tento objekt. Pokud my nějaký objekt od něj odvodíme, v tomto případě
C_MENU, můžeme tento odvozený objekt zařadit do pole, ale můžeme
přistupovat pouze k funkcím a proměnným, které zdědil (Draw(),
Test()). Ty jsou totiž shodné jak pro předka tak i pro potomka.
Pokud by jsme na poziti 0 uložili objekt C_MENU. Můžeme k němu
přistupovat asi takto :
gui.object_array[0]->Draw();
gui.object_array[0]->Test();
...
Pokud
bychom ale chtěli přistoupit k funkcím objektu C_MENU, musíme
položku 0 přetypovat na typ (C_MENU*)
(C_MENU*)(gui.object_array[0])->Show();
...
Tento zápis je poněkud kostrbatý a občas jsou s ním i problémy. Proto přidáme do objektu C_GUI tyto funkce :
|
Podrobně si rozepíšeme funkce pro C_BUTTON, ostatní je už pouhá analogie, jak pro C_MENU, tak i pro popisky, obrázky, atd.
|
Zapomněl jsem připomenout jednu důležitou věc. Pokud budeme takto ukládat do pole zděděné objekty a přistupovat k nim pomocí přetypování, může se stát, že se jedno hezkého dne spleteme a omylem přetypujeme objekt A na objekt B a program spadne. Proto jsem do C_GUI_OBJECT přidal proměnnou type, do které uložíme ID objektu (viz. minulý článek->definice). Pak pouze zkontrolujeme, jestli vracime ID == GUI_BUTTON, atd. A co chybový objekt? Co to je? Ano, zni to možná trochu divně. Představte si tuto situaci :
|
My tedy chceme získat ukazatel na tlačítko, které je uloženo na 50té pozici v našem poli. A potom změnit popisek tlačítka. Vše bude v pořádku až do chvíle, kdy buď bude položka 50 patřit jinému objektu (fce. by tedy měla vrátit NULL) nebo 50 bude mimo rozsah pole nebo položka nebude aktivní / použita. Ve všech třech případech by fce. měla vrátit onen NULL a při dalším kroku by program nejspíše zkolaboval. Zde se nabízejí dvě možnosti jak tento problém ošetřit :
|
To by šlo, ale já jsem člověk od přírody líný, tak jsem tu udělal asi takto. V unitě pro GUI jsem si nadefinoval pro každý objekt tzv. err_object, který je tam pouze pro případ podobné situace. Pokud k ni dojde, fce. nevrátí NULL, ale ukazatel na tento err_object a já s ním můžu vyvádět psí kusy a program se nezhroutí (snad).
|
A je to! Máme tu základní objekty, které jsou již skoro schopny práce. Zbývá nám nahrávání skriptů a obhospodařování GUI. Je to poněkud obsáhlejší, tak vás pro dnešek nechám oddychnout a těším se na vás příště.
Obsah seriálu (více o seriálu):
- Jak vyzrát na GUI - console
- Jak vyzrát na GUI - začátky GUI
- Jak vyzrát na GUI 3.díl - Tlačítka, menu, atd.
-
25. listopadu 2012
-
30. srpna 2002
-
10. října 2002
-
4. listopadu 2002
-
12. září 2002
-
25. listopadu 2012
-
28. července 1998
-
31. července 1998
-
28. srpna 1998
-
6. prosince 2000
-
27. prosince 2007
-
4. května 2007