Plynulß animace v MFC

Tady m∙₧ete stßhnout ukßzkovou aplikaci.

Pokud jste n∞kdy zkouÜeli vytvß°et pomocφ MFC n∞jakou hru, kterß pot°ebovala ΦastΘ p°ekreslovßnφ (animaci), urΦit∞ jste p°em²Üleli jak za°φdit aby animace nebyla trhanß. Kdy₧ pou₧ijete timer, tak i u timeru s velmi mal²m intervalem je znatelnΘ trhßnφ. Zp∙sob, kter² vßm ukß₧u podstatn∞ zkrßtφ interval p°ekreslovßnφ. U testovacφ aplikace, kde jsem m∞°il jak dlouho trvß tisφckrßt p°ekreslit jednoduch² °ßdek textu pomocφ timeru a stotisφckrßt (abych v∙bec n∞co nam∞°il) to samΘ pomocφ metody, kterou budu popisovat jsem zφskal tyto hodnoty (pomocφ funkce clock):

Timer: 52120 cykl∙  na tisφc p°ekreslenφ
Run: 1640 cykl∙ na stotisφc p°ekreslenφ

To znamenß, ₧e metoda pomocφ Run je 3178 krßt rychlejÜφ.

A te∩ koneΦn∞ p°edvedu jak to ud∞lat. Princip spoΦφvß v tom, ₧e mφsto abychom p°ekreslovßnφ provßd∞li v reakci na timer, p°ekreslenφ vyvolßvßme v p°etφ₧enΘ funkci CWinApp::Run. Tato funkce p∙vodn∞ obsahuje hlavnφ smyΦku aplikace GetMessage, TranslateMessage, DispatchMessage, jak to znßme z API WinMain.

Ne₧ se pustφme do jejφho p°episovßnφ musφme si napsat krßtk² pomocn² k≤d. Nejd°φve si v naÜφ t°φd∞ aplikace vlo₧φme public ukazatel na naÜi t°φdu pohledu (nazvan² pView) a v konstruktoru jej nastavφme na NULL.

Potom musφme tento ukazatel nastavit, aby ukazoval na nßÜ pohled. To se nejlΘpe ud∞lß v naÜφ t°φd∞ pohledu v reakci na zprßvu WM_CREATE (funkce OnCreate) a to takto:

Zφskßme ukazatel na naÜi t°φdu aplikace (nazvanou CTstApp):

CTstApp* pApp = NULL;

pApp = ((CTstApp*)AfxGetApp());

Nastavφme ukazatel ve t°φd∞ aplikace aby ukazoval na nßÜ pohled:

pApp->pView = this;

Abychom p°edeÜli pokusu k p°φstupu k neexistujφcφmu oknu, musφme tento ukazatel v reakci na zprßvu WM_DESTROY (funkce OnDestroy) nastavit op∞t na NULL a to nap°φklad takto:

CTstApp* pApp = NULL;

pApp = ((CTstApp*)AfxGetApp());

pApp->pView = NULL;

Te∩ jeÜt∞ musφme do naÜφ t°φdy pohledu p°idat funkci, kterß bude vlastnφ p°ekreslenφ  provßd∞t (nazveme ji t°eba Redraw). Jejφ obsah nechßm na vßs. Pro vyvolßnφ p°ekreslenφ m∙₧ete pou₧φt funkce Invalidate, RedrawWindow a nebo p°φmo zavolat OnPaint.

A nakonec ta hlavnφ Φßst. Ve svΘ t°φd∞ aplikace p°et∞₧te virtußlnφ funkci CWinApp::Run (jde to i pomocφ ClassWizardu). Pokud pou₧ijete ClassWizard dostanete takto vypadajφcφ funkci Run, kterß d∞lß jen to, ₧e volß funkci Run svΘho p°edka.

int CTstApp::Run()

{

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

return CWinApp::Run();

}

Vy jφ musφte upravit takto:

int CTstApp::Run()

{

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

MSG msg;

 

while(1)

{

if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))    // Pokud je ve front∞ zprßva zpracujeme ji

{

if (msg.message==WM_QUIT) break;    // Pokud je zprßva WM_QUIT ukonΦφme smyΦku (a tφm i aplikaci)

TranslateMessage(&msg);

DispatchMessage(&msg);

}

else    // Jinak vyvolßme p°ekreslenφ

{

if (pView) pView->Redraw();

}

}

 

return 0;

}

Novß verze funkce Run obsahuje nekoneΦnou smyΦku, kterß je p°eruÜena jen kdy₧ p°ijde zprßva WM_QUIT. V tΘto smyΦce se pomocφ funkce PeekMessage testuje zda je ve front∞ n∞jakß zprßva a pokud je, tak se zpracuje, jinak se vyvolß p°ekreslenφ. Tφm mßme zajiÜt∞no, ₧e se nejd°φve zpracujφ zprßvy a a₧ v p°φpad∞, ₧e ve front∞ zprßv nenφ ₧ßdnß zprßva se vyvolß p°ekreslenφ.

SouΦasn∞ s p°ekreslenφm by se m∞l vyvolßvat i p°epoΦet poloh animovan²ch objekt∙, aby trhßnφ nezp∙soboval namφsto pomalΘho p°ekreslovßnφ pomal² p°epoΦet pozic.

A to je vÜe.