P R O G R A M U J E M EC++ pod Windows / 9. èas : Dialógy IZaèal sa nám mesiac apríl, alebo ako ho mnohí <strong>na</strong>zývajú, mesiac bláznov. A práve titulom„blázni“ mnohí oz<strong>na</strong>èujú nás – poèítaèových <strong>na</strong>dšencov. Veï preèo nie? Každý jesvojím spôsobom blázon do nieèoho iného. Niekto si kupuje každý mesiac nový mobil,iný zas nové auto (teda ten lepšie zarábajúci J), niekto sa „vytešuje“ z novej kroniky¾udstva, iný z krásnej novej gitary, niekto pozerá Star Trek 325-krát za sebou a taktoby sme mohli ís donekoneè<strong>na</strong>. Otázkou však je, preèo niektorí ¾udia uvažujú takto:„Tebe sa páèi váž<strong>na</strong> hudba, mne nie, a preto sa s tebou už nikdy viac nebudem bavi .“Alebo: „Ako môžeš vidie krásu v tom, celý deò rozobera rádiá a potom ich znova<strong>sk</strong>lada ? Zbohom!“ A èo je pritom zaujímavé, ten istý èlovek môže vyslovi aj takútovetu: „Máš pekný oblek, my si urèite budeme rozumie !“ Nezdá sa vám to trochu „strelené“?Èo keby sme tak <strong>sk</strong>úsili posudzova ¾udí nie pod¾a toho, ako hovoria a ako saobliekajú, ale pod¾a toho, èo hovoria a ako rozmýš¾ajú. Ak sa vám tieto slová zdajúpovedomé, máte pravdu. Naozaj sú to trošku upravené slová z manifestu istej komunity,ktorá sa zaoberá vecami okolo poèítaèov. Èi sú pravdivé a správne, nechám <strong>na</strong>posúdenie každému z vás.No vrá me sa radšej k Visual C++. Ako vidie z <strong>na</strong>dpisu, zaèí<strong>na</strong>me prebera rozsiahlutému, ktorá je nepochybne jednou z <strong>na</strong>jzaujímavejších pre zaèiatoèníkov v programovanívo Visual C++, ale aj v iných prostrediach. Je to totiž jed<strong>na</strong> z prvých príležitostí,keï môžete vidie výsledky svojej práce, èo vás urèite minimálne motivuje <strong>na</strong>ïalšiu prácu. Na zaèiatok tejto èasti si však ešte nieèo povieme o objektoch GDI a triedachkontextu zariadenia knižnice MFC.Ako ste si urèite všimli, zmizla èas Tipy <strong>na</strong> WWW, keïže som vyèerpal takmer celúzásobu dobrých linkov. Tipy <strong>na</strong> stránky sa, samozrejme, budú <strong>na</strong>ïalej vy<strong>sk</strong>ytova , alebudú zaèlenené buï do úvodu, alebo záveru. Nová vec, ktorú som pridal, je FAQ. Tentovýraz oz<strong>na</strong>èuje (ako iste všetci viete) po anglicky Frequently A<strong>sk</strong>ed Questions èiže èastokladené otázky. V tejto èasti budeme uverejòova odpovede <strong>na</strong> vaše otázky, ktoré došlie-mailom (a je ich už neúrekom) a sú všeobecnejšieho charakteru, takže môžu pomôcaj iným. Je to taká menšia obdoba Programátor<strong>sk</strong>ej poradne pre Visual C++. Vašeotázky sa môžu, ale nemusia týka práve preberanej témy v tej-ktorej èasti seriálu(musia sa, samozrejme, týka programovania v C++). Takže píšte mi a pýtajte sa <strong>na</strong>všetko, èo vám nebude jasné, prípadne èo neviete vo Visual C++ urobi . Nezabudnite,kto sa niè nepýta, niè sa nedozvie!KONTEXT ZARIADENIA A OBJEKTY GDI V MFC. V seriáli sme užpracovali s kontextom zariadenia a dokonca aj s objektmi GDI. Vo funkcii OnDraw smeodovzdávali ukazovate¾ <strong>na</strong> kontext zariadení (pDC), vo funkcii OnLButtonDown smevytvárali objekt kontextu zariadení (CClientDC dc(this);) a používali sme objekty GDI systémovéhozásobníka (SelectStockObject(GRAY_BRUSH);).Kontext zariadenia: Základná trieda pre kontext zariadenia je trieda CDC. Od nej súpotom odvodené ïalšie: CClientDC, CWindowDC, CPaintDC... (podrobne pozri help).Rozdiely medzi týmito triedami sú nepatrné, <strong>na</strong>príklad objekt triedy CClientDC môžepristupova len ku klient<strong>sk</strong>ej èasti ok<strong>na</strong>, ale objekt triedy CWindowDC môže pristupovaaj ku klient<strong>sk</strong>ej, aj k neklient<strong>sk</strong>ej èasti ok<strong>na</strong>. Takže je len <strong>na</strong> vás, ako programátoroch,akú triedu si vyberiete pre vašu aplikáciu. Keï ešte presne neviete, èo sa bude odvašej aplikácie požadova , odporúèam vám <strong>na</strong>jprv používa objekt triedy CDC (èiže tejzákladnej triedy pre kontext zariadenia) a ne<strong>sk</strong>ôr, keï si už budete istí, rozhodnitesa pre niektorého potomka triedy CDC. Azda len pripomeniem, že ukazovate¾ <strong>na</strong>objekt, ktorý sa odovzdáva ako parameter funkcie OnDraw, je ukazovate¾om <strong>na</strong> objekttriedy CDC.Objekty GDI: Základná trieda pre všetky objekty GDI (Graphic Device Interface) systémuWindows je abstraktná trieda CGdiObject. Každá ïalšia trieda nejakého objektu GDIje odvodená od tejto triedy. Opis týchto odvodených tried je v helpe, takže <strong>na</strong> tomtomieste si ich len vymenujeme: CBitmap, CBrush, CFont, CPallete, CPen, CRgn. S niektorýmisme dokonca už aj pracovali (<strong>na</strong>pr. CPen).PRÁCA S OBJEKTMI TRIEDY CDC. Je dôležité vedie pracova s objektmikontextu zariadenia. Keï budeme potrebova <strong>na</strong>príklad nieèo <strong>na</strong>písa do ok<strong>na</strong> aplikácie(a to sa stáva ve¾mi èasto) a potrebujeme tak urobi z funkcie, ktorá nemá akoparameter ukazovate¾ <strong>na</strong> objekt triedy kontextu zariadenia, musíme vedie , ako vytvoria zruši takýto objekt. Naopak, ak používame kontext zariadení v nejakej funkcii,kde sa ukazovate¾ <strong>na</strong> objekt kontextu zariadení odovzdáva ako parameter (<strong>na</strong>pr. funkciaOnDraw), nemusíme sa vôbec stara o konštrukciu a deštrukciu (ruši takýto objektdokonca ani nesmieme!) tohto objektu, aplikaèný systém s MFC urobia túto prácu zanás. Ale ak <strong>na</strong>príklad vytvárame náš vlastný kontext zariadenia vo funkcii OnLButton-Down (robili sme tak v programoch First a Hi), musíme si tento objekt sami <strong>sk</strong>onštruovaa v istých prípadoch ho musíme aj sami zruši . Rušenie objektov kontextuzariadenia je nesmierne dôležité, pretože Windows má obmedzený poèet kontextovzariadení, ktoré môže vytvori , a pri ich nedôslednom používaní sa môže ¾ahko sta , ževáš program spadne, lebo nemohol vytvori ïalší kontext zariadenia (a verte mi, takétochyby sa odha¾ujú pomerne ažko). Existujú dva spôsoby vytvorenia nového objektukontextu zariadenia. Prvým je vytvorenie <strong>na</strong> stacku (tento spôsob bol použitý ajv programoch First a Hi). Má tú výhodu, že sa nemusíme stara o zrušenie takto vytvorenéhoobjektu. Aplikaèný systém to urobí za nás pri ukonèení funkcie, v ktorej smeobjekt vytvárali (teda <strong>na</strong>pr. OnLButtonDown). Ukážku tohto spôsobu vidíte tu:void CKontextView::OnLButtonDown(UINT nFlags, CPoint point){// vytvoríme objekt dc <strong>na</strong> stackuCClientDC dc(this);dc.TextOut(0, 0, “Tu som”);} // objekt dc je zrušenýParametrom konštruktora objektu dc je ukazovate¾ <strong>na</strong> okno (aby bolo systému jasné,ktorého ok<strong>na</strong> sa týka vytvorenie nového objektu kontextu zariadenia).No ak z rôznych príèin nechceme vytvára objekt <strong>na</strong> stacku, môžeme ho vytvori ajpomocou funkcie GetDC, ktorá je èlen<strong>sk</strong>ou funkciou triedy CWnd (toto je ten druhý spôsob).V tomto prípade zí<strong>sk</strong>ame ukazovate¾ <strong>na</strong> kontext zariadenia. Tu je príklad:void CKontextView::OnLButtonDown(UINT nFlags, CPoint point){// vytvoríme ukazovate¾ <strong>na</strong> kontext zariadeniaCDC* pDC=GetDC();}pDC->TextOut(0, 0, “Tu som”);// Dôležité! Musíme uvo¾ni kontext zariadeniaReleaseDC(pDC);Ako sme už uviedli, nesmieme zabudnú takto vytvorený ukazovate¾ aj sami zrušipomocou funkcie ReleaseDC.Takže teraz už viete, ako postupova pri vytváraní a rušení objektov kontextu zariadenia,a nemal by by pre vás problém z hocijakej funkcie realizova výstup <strong>na</strong> obrazovku.PRÁCA S OBJEKTMI GDI. Každý objekt GDI má iný konštruktor, a preto sanebudeme bližšie zaobera opisom každého z nich (tu vás opä odporuèím <strong>na</strong> help).Spomenieme si len, ako sa rušia tieto objekty. Ak èakáte nejakú funkciu podobnú ReleaseDC,ste <strong>na</strong> omyle (táto funkcia v urèitých prípadoch dokáže odstráni aj objekty GDI– pozri ïalej). Pri vytváraní, ale i rušení objektov GDI sa využíva funkcia SelectObject. Privytváraní nám táto funkcia vracia ten objekt GDI, ktorý je v nej aktuálne vložený, a zároveòvkladá novo vytvorený objekt, no a pri rušení využijeme tento vrátený predchádzajúciobjekt, ktorým jednoducho prepíšeme náš nový vložený objekt (ak máte v tom miernychaos, pozrite si tento príklad):void CKontextView::OnLButtonDown(UINT nFlags, CPoint point){// vytvoríme nový kontext zariadeniaCDC *pDC=GetDC();// vytvoríme objekt GDI pera// použijeme ho <strong>na</strong> vykreslenie elipsyCPen newPen(PS_SOLID, 6, RGB(0, 0, 255));// zí<strong>sk</strong>ame aktuálny objekt GDI (oldPen), ktorý ne<strong>sk</strong>ôr použijeme <strong>na</strong>// odstránenie objektu GDI newPen// zároveò tento aktuálny objekt GDI (oldPen) <strong>na</strong>hradíme// novým objektom GDI newPenCPen *oldPen=pDC->SelectObject(&newPen);// vykreslíme elipsu pomocou objektu GDI newPenpDC->Ellipse(0, 0, 400, 200);// z kontextu zariadenia vyberieme nový objekt GDI newPen// a vložíme tam predchádzajúci objekt GDI oldPenpDC->SelectObject(oldPen);}// uvo¾níme kontext zariadeniaReleaseDC(pDC);Ešte pár slov o funkcii ReleaseDC. Táto funkcia, ako už viete, odstráni kontext zariadenia,ktorý jej odovzdáme ako parameter (presnejšie povedané, odovzdávame ukazovate¾<strong>na</strong> tento kontext zariadenia, v tomto prípade je ním pDC). No ak máme k tomutokontextu zariadenia priradené nejaké objekty GDI, odstránia sa aj tie? Odpoveï znie:áno. Ak teda viete a ste si istí, že kontext zariadenia bude zrušený <strong>sk</strong>ôr ako objekty GDIk nemu priradené, nemusíte tieto objekty GDI už ruši , staèí zruši kontext zariadenia.Existuje ešte jeden spôsob, ako zruši objekty GDI, a to použitím objektov GDI systémovéhozásobníka. Tento postup sme si už opisovali vo štvrtej èasti, takže sa k nemu ne-108 PC REVUE 4/2001
P R O G R A M U J E M EJeho typ Iko<strong>na</strong> OpisMB_OK - zobrazí sa len tlaèidlo OKMB_OKCANCEL - zobrazia sa tlaèidlá OK a CancelMB_RETRYCANCEL - zobrazia sa tlaèidlá Retry a CancelMB_YESNO - zobrazia sa tlaèidlá Yes a NoMB_YESNOCANCEL - zobrazia sa tlaèidlá Yes, No a CancelMB_ABORTRETRYIGNORE - zobrazia sa tlaèidlá Abort, Retry a IgnoreMB_APPLMODAL - nebudete môc pracova s aplikáciou, pokým informaèné oknonezavriete; môžete však pracova s inými aplikáciamiMB_SYSTEMMODAL - nebudete môc pracova so systémom ani s ïalšou aplikáciou,pokým nezavriete informaèné okno (informaèné okno zostávastále <strong>na</strong> obrazovke aj pri práci s inou aplikáciou)MB_TASKMODAL - podobné ako APPLMODAL, neúèinný v aplikácii, ktorá využíva MFCMB_DEFBUTTON1 - urèuje „Default Button“ v dialógu (teda ten, ktorý sa aktivujepo stlaèení enter); používa sa pri viactlaèidlových informaènýchoknách (<strong>na</strong>pr. MB_ABORTRETRYIGNORE); <strong>na</strong>stavuje prvétlaèidlo ako defaultMB_DEFBUTTON2 - Nastavuje druhé tlaèidlo ako defaultMB_DEFBUTTON3 - Nastavuje tretie tlaèidlo ako defaultMB_ICONASTERISKZobrazí ikonualebo MB_ICONINFORMATIONMB_ICONEXCLAMATIONZobrazí ikonualebo MB_ICONWARNINGMB_ICONQUESTIONZobrazí ikonuMB_ICONHAND alebo MB_ICONSTOPalebo MB_ICONERRORTab. 1Typy informaèných dialógovZobrazí ikonubudem vraca (<strong>sk</strong>úste si však <strong>na</strong> domácu úlohu prerobi funkciu CKontextView::OnLButtonDown tak, aby ste využívali objekt GDI systémového zásobníka).ZAÈÍNAME DIALÓGMI. Na zaèiatok si hádam ujasnime, èo to vlastne dialógje. Dialóg je okno ako každé iné, môže spracúva správy, môžeme s ním robi operácieako s každým iným oknom (zavrie , premiestni , zmeni ve¾kos ). V systéme Windowsexistujú dva druhy dialógov: modálne a nemodálne. Modálne dialógy sú bežnejšie.Tento typ dialógov neumožòuje používate¾ovi vykonáva ïalšiu èinnos v danej aplikácii,pokým ho neuzavrie (príkladom takýchto dialógov sú dialógy Open, Save as, ale ajtzv. informaèné dialógy, <strong>na</strong>pr. This program has performed an illegal operation...).Nemodálne dialógy, ako už istotne tušíte, sa líšia od modálnych v tom, že umožòujúïalšiu prácu s aplikáciou (<strong>na</strong>pr. dialóg Find vo Worde). Z h¾adi<strong>sk</strong>a knižnice MFC savšak tieto dva typy dialógov nijako zvláš nelíšia. Obidva majú základnú triedu CDialog,rozdiel je len v ich vytváraní a rušení. Teraz zaèneme s tým <strong>na</strong>jjednoduchším, èo námknižnica MFC ponúka, a síce budú to informaèné dialógy, i<strong>na</strong>k známe ako Messageboxy.VYTVÁRAME MESSAGEBOX. Použitie tohto typu modálnych dialógov si <strong>na</strong>jlepšieukážeme <strong>na</strong> príklade. Chceme, aby sa po stlaèení ¾avého tlaèidla myši zobrazil informaènýdialóg s nejakým textom a, samozrejme, s ikonkou. Pomocou AppWizardu sivytvorte novú aplikáciu s názvom Information. Typ aplikácie bude rov<strong>na</strong>ký, aký sme používalidoteraz, èiže zvo¾te Single Document Interface a ostatné parametre nechajte <strong>na</strong>default. Ak už máte vygenerovanú základnú kostru aplikácie, potom pomocou Class Wizardupridajte obsluhu správy WM_LBUTTONDOWN do triedy CInformationView. Terazzmeòte kód funkcie OnDraw v tejto triede takto:void CInformationView::OnDraw(CDC* pDC){pDC->TextOut(0, 0, “Stlac lave tlacidlo mysi <strong>na</strong> zobrazenie informacnehodialogu.”);}MB_DEFBUTTON2 | MB_ICONINFORMATION);MessageBox(“Môj prvý dialóg v prostredí Visual C++”, “Hurá!”,MB_ABORT-RETRYIGNORE |MB_SYSTEMMODAL | MB_DEFBUTTON3 | MB_ICONINFORMATION);MessageBox(“Môj prvý dialóg v prostredí Visual C++”, “Hurá!”,MB_YESNO| MB_DEFBUTTON2 |MB_ICONWARNING);Aby sme videli použitie funkcie MessageBox v praxi, dopíšte tento kód do funkcieOnLButtonDown v aplikácii Information.void CInformationView::OnLButtonDown(UINT nFlags, CPoint point){MessageBox(“Môj prvý dialóg v prostredí Visual C++”, “Hurá!”, MB_OK |MB_ICONINFORMATION);}Teraz sa po stlaèení ¾avého tlaèidla myši v okne aplikácie zobrazí informaèný dialóg,ako vidíte <strong>na</strong> obr. 1. Pohrajte sa trochu s týmto jedným riadkom, zmeòte parametre funkciepod¾a tabu¾ky, vy<strong>sk</strong>úšajte rôzne kombinácie. To¾ko o dialógoch v tejto èasti, <strong>na</strong>budúce sapozrieme <strong>na</strong> klasické modálne dialógy so všetkým, èo k nim patrí, vrátane mechanizmuvýmeny údajov medzi ovládacími prvkami a premennými v programe a práce s editoromzdrojov.FAQ. V tejto „podèasti“ seriálu C++ pod Windows dávam priestor vám èitate¾om, abyste kládli otázky o programovaní vo Visual C++, <strong>na</strong> ktoré sa pokúsim odpoveda . V tejtoèasti uverejòujem dve otázky, ktoré mi prišli ešte v zaèiatkoch seriálu:Q: Nejde mi <strong>sk</strong>ompilova /zlinkova program Hello z druhej èasti seriálu.A: Tu je návod, ako postupova pri zostavovaní projektu Hello world z druhej èastiseriálu: Ak máte spustené Visual C++, z menu File vyberte New. Kliknite <strong>na</strong> záložkuProjects a vyberte Win32 Application.Do políèka Project Name zadajte Hello.Kliknite <strong>na</strong> OK. Objaví sa vám ïalší dialóg,<strong>na</strong> ktorom zvo¾te: An EmptyProject a kliknite <strong>na</strong> Finish. Potom savám zobrazia informácie o novom projekte.Opä kliknite <strong>na</strong> OK. Potom zmenu Project vyberte Add Tto Project apotom Files. Nájdite súbor, ktorý obsahujezdrojový text programu a vyberteAdd. Ak ešte nemáte <strong>na</strong>písaný zdrojový text, z menu Add To Project vyberte New apotom pod záložkou Files vyberte: C++ Source File. Na tom istom dialógu do políèkaFile <strong>na</strong>me vpíšte: hello.c. Je dôležité, aby prípo<strong>na</strong> súboru bola *.c, a nie *.cpp. Potom<strong>na</strong>píšte zdrojový kód do tohto súboru. Projekt zostavte.Q: Nejde mi <strong>sk</strong>ompilova /zlinkova program First zo štvrtej èasti seriálu, prièom mi hlásinejaký problém s knižnicou <strong>na</strong>fxcwd.lib.A: Postup pri vytváraní nového projektu je podobný ako pri programe Hello (pozri predchádzajúcuodpoveï). Tu však ešte treba zvoli podporu pre knižnicu MFC v danom projekte.Z menu Project vyberte Settings. V zoz<strong>na</strong>me Microsoft Fundation Classes vyberte<strong>na</strong>miesto Not Using MFC: Use MFC in a Shared DLL alebo Use MFC in a Static Library. Projekt<strong>na</strong>novo <strong>sk</strong>ompilujte a zlinkujte (Rebuild All).TIPY NA DOMA. Väèšinu tipov <strong>na</strong> doma nájdete v predchádzajúcom texte. Natomto mieste vám len pripomeniem, aby ste nezabudli experimentova (<strong>na</strong>pr. s funkciouMessageBox), lebo len samotným èítaním bez programovania sa ïaleko nedostanete.NABUDÚCE. O mesiac zaèneme <strong>na</strong>plno pracova s dialógmi, vytvoríme ve¾ký dialóg,ktorý bude obsahova väèšinu štandardných ovládacích prvkov, ktoré sa dajú použiv dialógoch. Vysvetlíme si mechanizmy DDX a DDV, a ak nám ostane priestor, zaènemesa venova aj spoloèným ovládacím prvkom Windows (Windows Common Controls).Dovidenia o mesiac.Marek ŠamajObr. 1 Informaèný dialóg programuInformationTeraz už používate¾ bude vedie , èo s aplikáciou robi . A ako sa vlastne vyvolá zobrazenieinformaèného dialógu? Ve¾mi jednoducho: staèí zavola funkciu MessageBox, prièomjej parametre sú:MessageBox(„Text v informaènom okne“, „Titulok informaèného ok<strong>na</strong>“,Jeho typ);Tretí parameter Jeho typ môže <strong>na</strong>dobúda hodnoty, ako vidíte v tab. 1. Treba si uvedomi, že tieto parametre môžeme kombinova . Odde¾ujeme ich operátorom |. Všetky<strong>na</strong>sledujúce volania funkcie MessageBox sú správne:MessageBox(“Môj prvý dialóg v prostredí Visual C++”, “Hurá!”,MB_ABORT-RETRYIGNORE |4/2001 PC REVUE 109