..:: Kurz MFC 2. dφl - ClassWizard, zprßvy a jednoduchΘ kreslenφ::..

V minulΘm dφle jsme si pomocφ AppWizardu vygenerovali kostru aplikace. V tomto dφle se dozvφte jak tuto kostru upravit, aby d∞lala to co chcete.

Ale nejd°φve jakß je vlastn∞ struktura MFC aplikace. MFC aplikace se sklßdß z jednΘ a vφce t°φd, jejich₧ p°edky jsou MFC t°φdy. Tyto MFC t°φdy majφ p°edprogramovanΘ urΦitΘ chovßnφ a tφm, ₧e v jejich potomcφch upravujete jednotlivΘ funkce a p°idßvßte novΘ tvo°φte svoji aplikaci.

Pokud jste vytvo°ili svoji aplikaci podle obrßzk∙ z minulΘho dφlu, vygeneroval vßm AppWizard t°φdy, kterΘ vidφte na nßsledujφcφm obrßzku vlevo uprost°ed v okn∞ workspace. Pokud na n∞jakou t°φdu poklepete, otev°e se vßm hlaviΦkov² soubor s deklaracφ tΘto t°φdy a pokud poklepete na n∞kterou jejφ funkci, tak se vßm otev°e soubor se zdrojov²m k≤dem tΘto funkce.

 

Tak₧e jak vidφte vygenerovalo se vßm p∞t t°φd a jedna globßlnφ prom∞nnß. Nßsleduje struΦn² popis t∞chto t°φd.

CAboutDlg  T°φda dialogu o aplikaci. Jejφm p°edkem je zßkladnφ t°φda vÜech dialog∙ CDialog. Vφce o dialozφch se dozvφte v n∞kterΘ z dalÜφch Φßstφ.
CMainFrame   T°φda hlavnφho rßmcovΘho okna aplikace. Jejφm p°edkem je zßkladnφ t°φda vÜech oken s rßmy CFrameWnd. Tato t°φda se starß o zobrazenφ titulku aplikace, menu, panelu nßstroj∙ a stavovΘho °ßdku.
CMfcApp T°φda aplikace. Jejφm p°edkem je CWinApp. Tato t°φda je ekvivalentem funkce WinMain. Ve skuteΦnosti ji obsahuje. Starß se o vytvo°enφ a zobrazenφ okna a v jejφ virtußlnφ funkci Run je obsa₧ena smyΦka GetMessage, TranslateMessage a DispatchMessage.
CMfcDoc T°φda dokumentu. Jejφm p°edkem je CDocument. Starß se o prßci s daty dokumetu jako je uklßdßnφ, naΦφtßnφ a vytvß°enφ novΘho dokumentu. (Nap°. kdy₧ zvolφte z menu polo₧ku nov² dokument.)
CMfcView T°φda pohledu. Jejφm p°edkem je CView. Starß se o zobrazovßnφ dat dokumentu. Je to ve skuteΦnosti okno rozta₧enΘ p°es celou klientskou plochu hlavnφho rßmcovΘho okna, tj. plochu kterou nezabφrß menu, panel nßstroj∙ a stavov² °ßdek. Samoz°ejm∞ lze kreslit i p°φmo na klientskou plochu hlavnφho rßmcovΘho okna a toto okno bychom nepot°ebovali, ale ₧ßdnß z mo₧nostφ AppWizardu vßm takovou aplikaci nevygeneruje, tak₧e by jste si ji museli napsat sami a takΘ by neÜly pou₧φvat n∞kterΘ pokroΦilejÜφ mo₧nosti.
theApp Toto nenφ t°φda, ale je to globßlnφ prom∞nnß t°φdy aplikace. Jejφm vytvo°enφm vlastn∞ cel² program zaΦφnß.

V tΘto lekci se soust°edφme na t°φdu pohledu (CMfcView) a jak v nφ odchytßvat zprßvy windows (nap°φklad od myÜi) a jak do nφ kreslit. Vytvo°φme si jednoduch² kreslφcφ program. JedinΘ co bude um∞t bude kreslenφ Φar do okna.

Nov² k≤d budu oznaΦovat tφmto zv²razn∞nφm.

Nejd°φve si musφme p°ipravit mφsto kam budeme nakreslenΘ Φßry uklßdat. Na zaΦßtek hlaviΦkovΘho souboru s deklaracφ t°φdy dokumentu p°ed tuto deklaraci p°idejte nßsledujφcφ °ßdky.

#include <afxtempl.h> // hlaviΦkov² soubor pro Üablony

 

struct LINE // struktura pro uklßdßnφ jednotliv²ch Φar

{

CPoint first,second;

};

 

typedef CArray<LINE,LINE&> LINES; // dynamickΘ pole Φar

a do nßsledujφcφ deklarace t°φdy dokumentu p°idejte prom∞nnou dynamickΘho pole Φar (LINES cary;) jak vidφte v nßsledujφcφm v²pisu

class CMfcDoc : public CDocument

{

protected: // create from serialization only

CMfcDoc();

DECLARE_DYNCREATE(CMfcDoc)

 

// Attributes

public:

LINES cary;

........

........

V p°edchßzejφcφm k≤du je pßr v∞cφ, kterΘ by asi cht∞ly vysv∞tlit. HlaviΦkov² soubor afxtempl.h obsahuje deklaraci a definici Üablon CArray, CList a CMap. Musφme jej vlo₧it, proto₧e pou₧φvßme CArray.

Definice struktury by m∞la b²t jasnß a₧ na typ pou₧it²ch prvk∙. Je to CPoint, co₧ je MFC t°φda, kterß zapouzd°uje strukturu POINT, kterß se pou₧φvß na urΦovßnφ bod∙. Tak₧e struktura vlastn∞ obsahuje dva body, zaΦßtek a konec ·seΦky.

V °ßdku s definovßnφm dynamickΘho pole Φar (typedef CArray......) je CArray Üablona t°φdy, kterß se chovß jako dynamickΘ pole. Pokud neznßte Üablony p°eΦt∞te si Φlßnek èablony v C++ na serveru www.eternal.cz 

A nakonec jsme p°idali prom∞nnou do t°φdy dokumentu. Ta je generovanß AppWizardem a m∞li by jste dokßzat pochopit jejφ strukutru, i kdy₧ neznßte MFC. Samoz°ejm∞ je tam pom∞rn∞ dost v∞cφ specifick²ch pro MFC a to Φemu nerozumφte by jste nem∞li m∞nit, proto₧e i zdßnlivΘ komentß°e jsou v MFC d∙le₧itΘ a pokud by jste je odstranili, tak by v nejlepÜφm p°φpad∞ nefungovali n∞kterΘ nßstroje Visual Studia (hlavn∞ ClassWizard).

Tφm mßme p°ipravenou pam∞¥ pro uklßdßnφ jednotliv²ch ·seΦek nßmi kreslen²ch Φar a m∙₧eme se pustit do programovßnφ vlastnφho kreslenφ.

Nejd°φve p°idßme do t°φdy pohledu (CMfcView) dv∞ pomocnΘ prom∞nnΘ "BOOL blbdown", kterß bube uklßdat stav levΘho tlaΦφtka myÜi (zda je stisknuto nebo ne) a "CPoint ptPrev", kterß bude uklßdat p°edchozφ polohu myÜi.

class CMfcView : public CView

{

protected: // create from serialization only

CMfcView();

DECLARE_DYNCREATE(CMfcView)

 

// Attributes

public:

CMfcDoc* GetDocument();

 

private:

BOOL blbdown;

CPoint ptPrev;

....

....

 

Te∩ jeÜt∞ v konstruktoru nastavφme prom∞nnou blbdown na FALSE;

CMfcView::CMfcView()

{

// TODO: add construction code here

blbdown = FALSE;

}

Te∩ musφme odchytit zprßvy od myÜi a to o stisknutφ (WM_LBUTTONDOWN), uvoln∞nφ (WM_LBUTTONUP) levΘho tlaΦφtka myÜi a o jejφm pohybu (WM_MOUSEMOVE). To provedeme pomocφ ClassWizardu. ClassWizard je k tomu p°φmo urΦen a nejen k tomu, ale o jeho dalÜφm vyu₧itφ napφÜi a₧ se dostaneme k dialog∙m.

Zprßvy lze zpracovßvat i jako v API v jednΘ funci (procedu°e okna). V MFC je to virtußlnφ Φlenskß funkce WindowProc t°φdy pohledu (jakΘhokoli okna). Postup ukß₧i na konci tohoto dφlu. 

Tak₧e zpßtky k odchytßvßnφ zprßv pomocφ ClassWizardu. Spustφte jej pomocφ menu View - ClassWizard. (Nebo klßvesovΘ zkratky CTRL+W.) V rozbalovacφm seznamu Class name vyberte t°φdu pohledu (CMfcView). PotΘ v seznamu Object IDs vyberte op∞t jmΘno t°φdy pohledu. (DalÜφ polo₧ky v tomto seznamu jsou identifikßtory polo₧ek menu a panelu nßstroj∙, kterΘ umo₧≥ujφ odchytit jejich stisk, ale o tom pozd∞ji.) Potom seznam Messages obsahuje seznam virtußlnφch funkcφ a zprßv se kter²mi umφ ClassWizard pracovat. Pokud se vßm n∞kdy stane, ₧e zde n∞jakou zprßvu nenajdete, tak se nelekejte, ₧e takovß zprßva neexistuje. ClassWizard neumφ zdaleka vÜechny zprßvy, jako dobr² p°φklad m∙₧e slou₧it zprßva WM_SYSCOMMAND, kterou zde nenajdete. Zprßvu namapujete tak, ₧e ji najdete v seznamu Messages, vyberete ji a stisknete tlaΦφtko Add Function. Potom jmΘno tΘto zprßvy v poli Messages bude zobrazeno tuΦn∞ a do seznamu Member functions se vßm p°idß jmΘno funkce, kterß se provede po obdr₧enφ tΘto zprßvy. Po zav°enφ ClassWizardu stiskem OK se vßm tyto funkce p°idajφ i do t°φdy pro kterou jste tyto zprßvy odchytßvali (t°idy vybranΘ v rozbalovacφm seznamu Class Name). Pokud budete chtφt zruÜit odchytßvßnφ n∞jakΘ zprßvy, staΦφ ji najφt v seznamu Messages a stisknout tlaΦφtko Delete Function. To sma₧e funkci z deklarace t°φdy, odstranφ zprßvu z mapy zprßv, ale definici funkce z cpp souboru musφte odstranit ruΦn∞.

Na nßsledujφcφm obrßzku vidφte stav ClassWizardu po namapovßnφ zprßv WM_LBUTTONDOWN a WM_LBUTTONUP a p°ed mapovßnφm zprßvy WM_MOUSEMOVE.

Pokud jste sprßvn∞ namapovali tyto t°i zprßvy m∞li by jste vid∞t odpovφdajφcφ funkce v okn∞ Workspace. Kdy₧ na n∞kterou z nich poklepete, tak se vßm v editoru otev°e jejφ zdrojov² k≤d jak m∙₧ete vid∞t na nßsledujφcφm obrßzku.

Parametry tΘto funkce jsou parametry zprßvy p°evedenΘ z WPARAM a LPARAM na odpovφdajφcφ typy. U t∞chto funkcφ (zprßv) majφ parametry v²znam: nFlags - p°φznaky, nap°. zda je stisknuto CTRL atd. Druh² parametr point je bod ve kterΘm byla myÜ, kdy₧ byla zprßva zaslßna. Bod je udßn v pixelech od levΘho hornφho rohu okna, kladn² sm∞r os je doprava a dol∙.

Tyto funkce upravφme takto:

 

Funkce OnLButtonDown se volß kdy₧ v okn∞ stiskneme levΘ tlaΦφtko myÜi (zprßva WM_LBUTTONDOWN).

void CMfcView::OnLButtonDown(UINT nFlags, CPoint point)

{

// TODO: Add your message handler code here and/or call default

// Nastavφme pomocnou prom∞nnou blbdown na TRUE -> je stisknuto levΘ tlaΦφtko myÜi.

blbdown=TRUE;

// Pomocnou prom∞nnou ptPrev nastavφme na pozici kurzoru v okam₧iku kdy bylo tlaΦφtko stisknuto.

ptPrev = point;

 

/*

Nakonec je ponechßno volßnφ funkce OnLButtonDown zßkladnφ t°φdy.

Tφm zajistφme, ₧e pokud mß zßkladnφ t°φda naprogramovanou n∞jakou obsluhu

tΘto udßlosti (stisku levΘho tlaΦφtky myÜi), tato obsluha se provede a tφm se

zachovß funkΦnost i z p°edka naÜφ t°φdy.

*/

CView::OnLButtonDown(nFlags, point);

}

 

Funkce OnLButtonUp se volß kdy₧ v okn∞ uvolnφme levΘ tlaΦφtko myÜi (zprßva WM_LBUTTONUP).

void CMfcView::OnLButtonUp(UINT nFlags, CPoint point)

{

// TODO: Add your message handler code here and/or call default

// Pomocnou prom∞nnou blbdown nastavφme na FALSE -> levΘ tlaΦφtko nenφ stisknuto.

blbdown = FALSE;

 

CView::OnLButtonUp(nFlags, point);

}

 

Funkce OnMouseMove se volß kdy₧ v okn∞ pohneme myÜφ (zprßva WM_MOUSEMOVE).

void CMfcView::OnMouseMove(UINT nFlags, CPoint point)

{

// TODO: Add your message handler code here and/or call default

Nejd°φve si nadefinujeme t°i prom∞nnΘ. line je Φßra kterou potΘ p°idßme do naÜeho pole v dokumentu. pDoc je ukazatel na nßÜ dokument. Tento ukazatel zφskßte pomocφ funkce pohledu GetDocument(). dc je instance t°φdy CClientDC jejφmu₧ konstruktoru jsme p°edali jako parametr ukazatel na okno ve kterΘm pracujeme. T°φda CClientDC je MFC t°φda, kterß je potomkem jinΘ MFC t°φdy CDC. T°φda CDC zapouzd°uje HDC (kontext za°φzenφ) z API a pou₧φvß se (bu∩ p°φmo ona nebo jejφ potomci) pro jakΘkoli kreslenφ do okna. Pokud trochu znßte API tak jist∞ vφte, ₧e ne₧ se zaΦne kreslit do okna, m∞ly by se provΘst n∞jakΘ p°φpravy. V MFC za vßs tyto p°φpravy provede tato t°φda (v konstruktoru) a starß se i o uvoln∞nφ kontextu za°φzenφ HDC (co₧ je jejφ Φlenskß prom∞nnß) po skonΦenφ kreslenφ (v destruktoru). Tak₧e pokud chcete kreslit do kterΘhokoli okna vaÜφ aplikace, staΦφ vytvo°it instanci t°φdy CClientDC jejφmu₧ konstruktoru p°edßte ukazatel na toto okno.

LINE line;

CMfcDoc* pDoc = GetDocument();

CClientDC dc(this);

Pokud je stisknuto levΘ tlaΦφtko myÜi, naplnφme strukutru Φßry p°edchßzejφcφ a souΦasnou polohou myÜi, nastavφme p°edchßzejφcφ polohu myÜi na souΦasnou a p°idßme Φßru do dynamickΘho pole v dokumentu. Potom pomocφ funkcφ MoveTo a LineTo vykreslφme Φßru od p°edchßzejφcφ polohy myÜi k souΦasnΘ. Funkce MoveTo nastavφ zaΦßtek Φßry a funkce LineTo nakreslφ Φßru od bodu urΦenΘho p°edchozφm volßnφm MoveTo (nebo LineTo).

if (blbdown)

{

line.first = ptPrev;

line.second = point;

ptPrev = point;

pDoc->cary.Add(line);

dc.MoveTo(line.first);

dc.LineTo(line.second);

}

 

CView::OnMouseMove(nFlags, point);

}

Pokud by jste te∩ aplikaci p°elo₧ili a spustili tak zjistφte, ₧e u₧ vßm umo₧≥uje kreslenφ. Ale pokud okno minimalizujete, nebo p°ekryjete jin²m, tak zjistφte, ₧e vßm nakreslenΘ Φßry zmizely. To je zp∙sobeno tφm, ₧e okno poka₧dΘ, kdy₧ je p°ekryto, pot°ebuje p°ekreslit. O to se musφte takΘ postarat sami. Poka₧dΘ, kdy₧ okno pot°ebuje p°ekreslit, dostane zprßvu WM_PAINT. Tentokrßt ji vÜak nebudeme odchytßvat pomocφ ClassWizardu (ikdy₧ to takΘ m∙₧ete ud∞lat), proto₧e v zßkladnφ t°φd∞ pohledu (CVIew) je napsßna tak, ₧e volß virtußlnφ funkci OnDraw a jako parametr jφ p°edßvß ukazatel na t°φdu CDC pomocφ kterΘho m∙₧ete do tohoto okna kreslit. To znamenß, ₧e musφme upravit funkci OnDraw tak, aby vykreslovala vÜechny nßmi nakreslenΘ Φßry. AppWizard poΦφtß s tφm, ₧e budeme chtφt n∞co kreslit, tak₧e funkce OnDraw je ji₧ p°ipravena a staΦφ ji pouze upravit tak, aby kreslila to co chceme. 

Najd∞te si v t°φd∞ pohledu (CMfcView) funkci OnDraw a upravte ji takto:

void CMfcView::OnDraw(CDC* pDC)

{

CMfcDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

// TODO: add draw code for native data here

Postupn∞ projdeme vÜechny Φßry v dokumentu a vykreslφme je. PoΦet Φar (prvk∙ pole) zφskßme pomocφ ΦlenskΘ funkce GetSize() Üablony t°φdy CArray. Mo₧nß vßs zarazilo, ₧e k prvk∙m t°φdy p°istupuji pomocφ hranat²ch zßvorek jakoby to bylo obyΦejnΘ pole. To je umo₧n∞no dφky p°etφ₧enφ operßtoru [ ] (hranatΘ zßvorky). Mφsto toho by jste takΘ mohli pou₧φt Φlenskou funkci Üablony t°φdy CArray GetAt(), kterß vßm takΘ poskytne p°φstup k jednotliv²m prvk∙m tΘto Üablony t°φdy dynamickΘho pole, ale oprßtor [ ] umo₧≥uje i p°i°azovat hodnoty do tohoto pole ji₧ existujφcφm prvk∙m. Kreslenφ by jste u₧ takΘ m∞li chßpat. Je to totΘ₧ jako ve funkci OnMouseMove, a₧ na to, ₧e nepou₧φvßme t°φdu CClientDC, ale p°φmo t°φdu CDC (ktarß je jejφm p°edkem) a nemusφme si jejφ instanci vytvß°et sami, ale je nßm p°edßna jako parametr funkce OnDraw.

int i;

for(i=0; i<pDoc->cary.GetSize(); i++)

{

pDC->MoveTo(pDoc->cary[i].first);

pDC->LineTo(pDoc->cary[i].second);

}

}

Te∩ u₧ vßm obsah okna nezmizφ ani kdy₧ jej p°ekryjete jin²m oknem. 

Pokud jste zkouÜeli co tato aplikace dovede, jist∞ jste si vÜimli, ₧e nefungujφ povely panelu nßstroj∙ (nebo menu) pro otevφrßnφ, uklßdßnφ a vytvo°enφ novΘho dokumentu. Jak je zprovoznit se dozvφte v p°φÜtφm dφle, kter² se bude v∞novat t°φd∞ dokumentu.

 

JeÜt∞ jsem vßm slφbil ukßzat jak odchytßvat vÜechny zprßvy v jedinΘ funkci namφsto pomocφ ClassWizardu a mapy zprßv. (Tyto dva zp∙soby lze libovoln∞ kombinovat, jen nemapujte jednu zprßvu jak pomocφ ClassWizardu do mapy zprßv tak do tΘto funkce.) Ukß₧eme si to na odchycenφ zprßvy WM_SYSCOMMAND a tφm, ₧e ji v p°φpad∞, ₧e jejφ parametr wParam bude mφt hodnotu SC_MINIMIZE nezpracujeme (nebo lΘpe °eΦeno neprovedeme nic), zakß₧eme minimalizaci naÜφ aplikace.

Tak₧e zaΦneme tφm, ₧e si pomocφ ClassWizardu p°etφ₧φme virtußlnφ funkci WindowProc, kterß v MFC nahrazuje proceduru okna. Musφme ji p°etφ₧it pro rßmcovΘ okno (CMainFrame), proto₧e budeme odchytßvat zprßvu, kterß mß vliv na zobrazenφ celΘho okna a ne jen pohledu. Postup je stejn² jako u odchytßvßnφ zprßv pomocφ ClassWizardu jen tam kde jsme vybφrali t°φdu pohledu (CMfcView), tentokrßt vybereme t°φdu hlavnφho rßmcovΘho okna (CMainFrame) a mφsto zprßvy vybereme virtußlnφ funkci WindowProc jak je vid∞t na nßsledujφcφm obrßzku.

A potΘ tuto funkci upravφme jako by to byla procedura okna v API.

LRESULT CMainFrame::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)

{

// TODO: Add your specialized code here and/or call the base class

 

switch (message)

{

case WM_SYSCOMMAND:

if (wParam==SC_MINIMIZE) return 0;

break;

};

return CFrameWnd::WindowProc(message, wParam, lParam);

}

A to je v tΘto lekci vÜe.

Zdrojov² k≤d si m∙₧ete stßhnout zde.

<<1. dφl    3.dφl>>