Introduction :
Vous avez surement entendu parler des Timers, mais vous ne savez pas trop
comment les mettre en œuvre.
Cet article va vous monter qu'il n'y a rien de bien compliqué.
Un timer est un système qui envoie un signal régulier à une fréquence déterminée,
tel le métronome du musicien.
Dans l'exemple nous utiliserons deux timers pour faire clignoter deux rectangles
dessiné sur une fenêtre. Pourquoi deux, pour bien montrer la façon de les différencier.
Ils auront une fréquence différente. Ils pourront être démarrés ou arrêtés depuis le menu de l'application.
Mise en oeuvre :
Pour créer un timer il suffit d'appeler la fonction SetTimer
SetTimer(hwnd, ID_TIMER_1, 1000, NULL);
Le premier paramètre étant le handle de fenêtre à laquelle il est associé.
Le second étant un identificateur (constante numérique) que l'on lui attribut.
Le troisième étant le temps en millisecondes de son tempo.
Le quatrième que nous n'utiliserons pas, est un pointeur sur une fonction
de rappel qui est appelée à chaque signal de tempo.
Dans l'exemple nous utiliserons le message qui est envoyé à la fenêtre associé au timer
du timer.
(Si le timer n'avait pas été associé à une fenêtre, nous aurions été contrains
d'utiliser la fonction de rappel).
Ce message est WM_TIMER, il se traite comme les autres messages Windows dans la procédure de fenêtre,
comme ceux nous avons vu dans les autres chapitres.
Ce message dans son paramètre wParam contient l'identificateur du timer qui
envoie le message, identificateur que l'on avait passé en deuxième paramètre
à SetTimer et qui permet donc de savoir de quel timer il s'agit.
case WM_TIMER:
if(wParam == ID_TIMER_1)
{
/* action */
}
if(wParam == ID_TIMER_2)
{
/* action */
}
Quand vous ne voulez plus du Timer, il suffit de le détruire avec la fonction
KillTimer avec comme paramètre le handle de fenêtre et l'identificateur
du timer.
KillTimer(hwnd,ID_TIMER_1);
Pour illustrer l'exemple nos timers feront basculer de true à false et vice versa
deux variables booléennes nommées T1 et T2.
Ces variables permettront ensuite l'affichage ou non des rectangles dans le traitement
du message WM_PAINT.
Les timers sont démarrés ou arrêtés depuis les commandes du menu.
Code complet :
resource.h :
#define IDM_START_1 101
#define IDM_STOP_1 102
#define IDM_START_2 103
#define IDM_STOP_2 104
#define IDM_QUIT 105
resource.rc :
#include <windows.h>
#include "resource.h"
LEMENU MENU
BEGIN
POPUP "Fichier"
BEGIN
MENUITEM "Start Timer 1", IDM_START_1
MENUITEM "Stop Timer 1", IDM_STOP_1
MENUITEM SEPARATOR
MENUITEM "Start Timer 2", IDM_START_2
MENUITEM "Stop Timer 2", IDM_STOP_2
MENUITEM SEPARATOR
MENUITEM "Quitter", IDM_QUIT
END
END
winmain.c :
#include <windows.h>
#include "resource.h"
#define ID_TIMER_1 1
#define ID_TIMER_2 2
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
int nCmdShow)
{
HWND hwnd;
MSG msg;
WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(1 + COLOR_BTNFACE);
wc.lpszMenuName = "LEMENU";
wc.lpszClassName = "MaWinClass";
if(!RegisterClass(&wc)) return FALSE;
hwnd = CreateWindow("MaWinClass", "Timers", WS_OVERLAPPED | WS_SYSMENU,
CW_USEDEFAULT, CW_USEDEFAULT, 400, 260,
NULL, NULL, hInstance, NULL);
if (!hwnd) return FALSE;
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
/******************************************************************************/
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static BOOL T1 = TRUE;
static BOOL T2 = TRUE;
switch (uMsg)
{
case WM_CREATE:
return 0;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDM_QUIT :
PostMessage(hwnd, WM_CLOSE,0,0);
break;
case IDM_START_1 :
SetTimer(hwnd,ID_TIMER_1,1000,NULL);
break;
case IDM_START_2 :
SetTimer(hwnd,ID_TIMER_2,500,NULL);
break;
case IDM_STOP_1 :
KillTimer(hwnd,ID_TIMER_1);
T1 = TRUE;
InvalidateRect(hwnd,NULL,TRUE);
break;
case IDM_STOP_2 :
KillTimer(hwnd,ID_TIMER_2);
T2 = TRUE;
InvalidateRect(hwnd,NULL,TRUE);
break;
}
return 0;
case WM_TIMER:
if(wParam == ID_TIMER_1)
{
T1 = !T1;
InvalidateRect(hwnd,NULL,TRUE);
}
if(wParam == ID_TIMER_2)
{
T2 = !T2;
InvalidateRect(hwnd,NULL,TRUE);
}
return 0;
case WM_PAINT :
{
HBRUSH hbNew, hbrOld;
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
hbNew = CreateSolidBrush(0x000000FF);
hbrOld = SelectObject(hdc,hbNew);
if(T1) Rectangle(hdc, 30, 20, 180, 170);
SelectObject(hdc,hbrOld);
DeleteObject(hbNew);
hbNew = CreateSolidBrush(0x00007F00);
hbrOld = SelectObject(hdc,hbNew);
if(T2) Rectangle(hdc, 210, 20, 360, 170);
SelectObject(hdc,hbrOld);
DeleteObject(hbNew);
EndPaint(hwnd, &ps);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
A savoir que si le timer n'est pas associé à une fenêtre,
c'est la valeur de retour de SetTimer qui sert d'identificateur à passer à
KillTimer pour le détruire. Il est possible de changer la fréquence d'un timer
déjà démarré par un second appel à SetTimer.
N'hésiter pas à consulter le site de msdn
pour plus d'informations sur les timers
A vos PC.
CGi
|