Časovače (MFC a C++)

Určitě jste ve svém programu už někdy potřebovali vykonávat nějakou operaci v zadaný čas nebo vždy za určitou dobu. K tomuto účelu slouží časovače, které si nyní blíže popíšeme.

Existují celkem tři možnosti, jak pomocí standardních API funkcí dosáhnout požadovaného výsledku. První je použití standardního časovače, druhá je pomocí multimediálních časovačů a třetí (nejpřesnější) pomocí performance counteru.

Standardní časovače

Tyto časovače se hodí zejména pro činnosti, které nejsou nezbytné pro chod programu, protože pokud právě program vykonává jinou operaci, tak se obsluha časovače neprovádí. Další celkem podstatná nevýhoda spočívá v tom, že nemůžete nastavit menší rozlišení než asi 50 milisekund. Proto bych tento způsob doporučil pouze pro aplikace typu Hodiny, kde má timer za úkol aktualizovat čas např. ve stavovém řádku. A nyní jak na to.

Pokud chceme časovač aktivovat, použijeme API funkci SetTimer, které předáme handle našeho okna, identifikační číslo timeru, dobu za kterou se vždy bude časovač obsluhovat a proceduru, která se bude volat po uplynutí nastavené doby. Pokud poslední parametr nastavíte na NULL, tak se místo toho budou posílat zprávy WM_TIMER.

UINT SetTimer(
  HWND hWnd,              // Handle okna
  UINT nIDEvent,          // Identifikační číslo timeru
  UINT uElapse,           // Rozlišení (v milisekundách)
  TIMERPROC lpTimerFunc   // Adresa funkce pro volání
);

//Příklad na volání

SetTimer(m_hWnd,1,50,NULL);

V příkladu na volání jsme časovač nastavili tak, aby se volal vždy každých 50 ms a to tak, že se budou oknu zasílat zprávy WM_TIMER. Na tyto zprávy můžeme reagovat jednoduše v proceduře okna, id timeru je uloženo v parametru wParam. Příklad na obsluhu:

LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
  switch(uMsg)
  {
    case WM_TIMER:
      if(wParam==1)
        MessageBox(hWnd,"Timer!","Info",MB_OK);
      break;
  }
  
  return DefWindowProc(hWnd,uMsg,wParam,lParam);
}

Poslední věc, kterou bychom měli udělat před ukončením aplikace, je zrušení timeru. To se provede pomocí funkce KillTimer, které předáme handle okna a číslo timeru ke zrušení.

Multimediální časovače

Jak už z názvu vyplývá, tyto časovače se používají nejčastěji ve spojení s multimédii a mají rozlišení až do 1 ms. Obsluha ovšem neprobíhá přes zprávy, ale přes funkce, protože tyto časovače vytvářejí v programu nové vlákno, které potom volá naší funkci, a proto byste neměli zapomenout na potřebnou synchronizaci.

První, co musíme udělat, je vložení hlavičkového souboru mmsystem.h a přilinkování knihovny winmm.lib. Dále je potřeba nadefinovat funkci pro obsluhu časovače a použít funkci timeSetEvent, která má následující parametry:

MMRESULT timeSetEvent(
  UINT uDelay,            		//Doba, za kterou se bude volat funkce    
  UINT uResolution,           		//Rozlišení
  LPTIMECALLBACK lpTimeProc,  		//Adresa funkce obsluhy
  DWORD dwUser,               		//Uživatelský parametr
  UINT fuEvent                		//Typ události
);

//Ukázka použití

//Definování obsluhy
void CALLBACK TimeProc(UINT uID,UINT uMsg,DWORD dwUser,DWORD dw1,DWORD dw2)
{
  MessageBeep(MB_OK);
}

//Nastavení časovače

UINT id=timeSetEvent(1,1,TimeProc,0,TIME_PERIODIC | TIME_CALLBACK_FUNCTION);

...

timeKillEvent(id);

Funkce ve své návratové hodnotě vrací identifikační číslo, které potom použijeme pro zrušení časovače, které se provádí pomocí funkce timeKillEvent, které předáme toto číslo.

Performance counter

Tento časovač se nepoužívá moc často, protože umožňuje pouze získávat čas v mikrosekundovém rozlišení a potom podle toho reagovat. Pokud se o něm chcete dozvědět více informací, doporučuji článek Přesné měření času na stránkách Farao.

UPOZORNĚNÍ: Jedná se o archiv článků z let 2003 - 2005, uvedené technologie či postupy již mohou být neaktuální.