Jestli jst u₧ zaΦali pou₧φvat postupy z minul²ch dvou dφl∙, mo₧nß jste si vÜimli dvou chyb. Ta prvnφ nenφ vß₧nß a pouze znep°φjemnφ ₧ivot programßtorovi. Zkrßtka a jednoduÜe pokud podle mΘho nßvodu z prvnφho dφlu p°epφÜete funkci Run, p°estanou vßm ve vaÜφ aplikaci fungovat klßvesovΘ zkratky (accelerators). Ta druhß je mnohem horÜφ a pravd∞podobn∞ na ni p°ijdete teprve a₧ zaΦnete testovat svou aplikaci na jinΘm PC. Pokud podle mΘho nßvodu zßrove≥ s p°ekreslenφm p°epoΦφtßvßte i pozice vykreslovan²ch objekt∙ tak rychlost jejich pohybu bude zßviset na ryhclosti PC. Tj. na n∞jakΘm starÜφm PC vßm hra p∙jde tou sprßvnou rychlostφ, a kdy₧ ji spustφte na n∞jakΘm extrav²konΘm poΦφtaΦi tak ani nebudete staΦit sledovat co se na obrazovce d∞je. (Jestli pamatujete tak stejn² problΘm byl i s hrami pro DOS.)
Ale nezoufejte. Ob∞ chyby jdou pom∞rn∞ jednoduÜe odstranit. ZaΦneme tou jednoduÜÜφ.
KlßvesovΘ zkratky se nep°eklßdajφ v procedu°e okna, ale jeÜt∞ p°edtφm ne₧ se zprßva do procedury okna dostane ve funkci PreTranslateMessage. A tφm jak jsme p°epsali funkci Run jsme zßrove≥ zruÜili jejφ volßnφ. Na odstran∞nφ je jednoduch² recept. Prost∞ tam to volßnφ p°idßme a funkce Run pak vypadß 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)
// Zavolßme funkci PreTranslateMessage. Ta vrßtφ TRUE pokud zprßvu zpracovala a nenφ t°eba ji posφlat do procedury okna.
if (!PreTranslateMessage(&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else // Jinak vyvolßme p°ekreslenφ
{
if (pView) pView->Redraw();
}
}
return 0;
}
Druhß chyba je horÜφ a to i na odstran∞nφ. Ty rozdφlnΘ rychlosti jsou zp∙sobeny tφm, ₧e se p°ekreslenφ volß v nekoneΦnΘm cyklu a ka₧d² poΦφtaΦ jej stihne provΘst za jinou dobu. Pomoc je takovßto. P°ekreslenφ vyvolat jen pokud ub∞hl urΦit² Φas. Te∩ je ale problΘm s tφm jak m∞°it ub∞hl² Φas s dostateΦnou p°esnostφ. Nabφdnu vßm dv∞ mo₧nosti. (Ale popφÜi jen tu jednoduÜÜφ.) K dostateΦn∞ p°esnΘmu m∞°enφ Φasu m∙₧ete pou₧φt bu∩ funkci timeGetTime, kterß vracφ Φas ub∞hl² od startu Windows v milisekundßch nebo dvojici funkcφ, kterΘ m∞°φ jeÜt∞ p°esn∞ji, ale jejich fungovßnφ zßvisφ na hardwaru a to QueryPerformanceFrequency (pro zjiÜt∞nφ frekvence) a QueryPerformanceCounter (pro zjiÜt∞nφ hodnoty kterß je na poΦφtadle, d∞lenφm tΘto hodnoty frekvencφ zφskßte Φas v sekundßch).
Funkce timeGetTime je deklarovßna v hlaviΦkovΘm souboru mmsystem.h a musφte jeÜt∞ vlo₧it lib soubor winmm.lib.
Potom bude funkce Run vypadat takto:
(Nßsledujφcφ k≤d p°edpoklßdß, ₧e mßte ve svΘ t°φd∞ p°idßny prom∞nnΘ
time_start a interval (typu DWORD) a prom∞nnou interval v
konstruktoru nastavenou na po₧adovan² interval p°ekreslenφ. M∞lo by staΦit
asi 25 (ms).)
int CTstApp::Run()
{
// TODO: Add your specialized code here and/or call the base class
MSG msg;
time_start = timeGetTime();
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)
// Zavolßme funkci PreTranslateMessage. Ta vrßtφ TRUE pokud zprßvu zpracovala a nenφ t°eba ji posφlat do procedury okna.
if (!PreTranslateMessage(&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else // Jinak vyvolßme p°ekreslenφ
{
if (pView)
{
if ((timeGetTime()-time_start)>=interval) // Pokud vyprÜel interval
{
pView->Redraw(); // P°ekreslφme
time_start = timeGetTime(); // Resetujeme interval
}
}
}
}
return 0;
}
Obdobn∞ je t°eba upravit i funkci vlßkna, pokud jej pou₧φvßte mφsto p°epsßnφ Run.
Nebo pro m∞°enφ Φasu m∙₧ete pou₧φt moji t°φdu CPeriod, kterou si m∙₧ete stßhnout zde a kterß umo₧≥uje m∞°enφ i pomocφ t∞ch p°esn∞jÜφch funkcφ.