Explorați Cărți electronice
Categorii
Explorați Cărți audio
Categorii
Explorați Reviste
Categorii
Explorați Documente
Categorii
#include <windows.h> int WINAPI WinMain(HINSTANCE d1, HINSTANCE d2, LPSTR d3, int d4) { MessageBox(NULL, "Hello, World!", "", MB_OK); } Bucla de mesaje i procedura fereastr sunt ascunse. MessageBox afieaz o box de dialog care conine procedura fereastr i deoarece boxa de dialog este modal (nu poate fi prsit fr a se da clic pe ...) practic se cicleaz pe bucla de mesaje.
Proceduri fereastr
#include <windows.h> // ---------------- Apelata pe mesajul WM_PAINT void DrawHello(HWND hwnd) { HDC hDC; PAINTSTRUCT paintStruct; RECT clientRect; hDC = BeginPaint(hwnd, &paintStruct); if (hDC != NULL) { GetClientRect(hwnd, &clientRect); DPtoLP(hDC, (LPPOINT)&clientRect, 2); DrawText(hDC, "Hello, World!", -1, &clientRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); EndPaint(hwnd, &paintStruct); } } // --------------------------- Procedura fereastra LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_PAINT: DrawHello(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; // trebuie sa intoarca totdeauna 0 (zero) } // --------------- Programul principal int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR d3, int nCmdShow) { MSG msg; HWND hwnd; WNDCLASS wndClass; if (hPrevInstance == NULL) // valabil numai pentru Windows 3.1 { memset(&wndClass, 0, sizeof(wndClass)); // stiluri de fereastra wndClass.style = CS_HREDRAW | CS_VREDRAW; wndClass.lpfnWndProc = WndProc; // procedura fereastra wndClass.hInstance = hInstance; // instanta aplicatiei wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); // resursa cursor wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
// resursa penson wndClass.lpszClassName = "HELLO"; // nume fereastra // inregistrare fereastra if (!RegisterClass(&wndClass)) return FALSE; // terminat if hwnd = CreateWindow("HELLO", "HELLO", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg); return msg.wParam;
} Explicaii: se creaz fereastra prin completarea structurii WNDCLASS; se nregistreaz fereastra RegisterClass(&wndClass); se creaz fereastra CreateWindow; se stabileste modul de afiare al ferestrei ShowWindow(hwnd, nCmdShow); se afieaz fereastra propriu zis UpdateWindow(hwnd); urmeaz bucla de mesaje. Codul ce trebuie urmrit este cel din WndProc, procedura fereastr. Ce mesaje sunt tratate? Care sunt rspunsurile aplicaiei la aceste mesaje? WndProc trateaz dou mesaje: WM_PAINT i WM_DESTROY. Alte mesaje dect cele indicate sunt tratate de ctre DefWindowProc. La mesajul WM_DESTROY se plaseaz n coada de mesaje, mesajul WM_QUIT care are ca efect terminarea buclei de mesaje, i deci terminarea aplicaiei. La mesajul WM_PAINT se apeleaz funcia DrawHello. Dar cnd este trimis mesajul WM_PAINT i de cine? Mesajul WM_PAINT este trimis prima dat de funcia UpdateWindow, adic atunci cnd fereastra devine vizibil prima dat. ncercai opiunile Size i Move din meniul sistem. Ce se ntmpl? Trebuie reinut urmtorul lucru: dac n coada de mesaje apar mai multe mesaje WM_PAINT, sistemul va trata numai ultimul mesaj. n fapt ultima redesenare a ferestrei rmne vizibil, restul afirilor ar fi consumatoare de timp i n plus ar crea i un efect neplcut datorat rdesenrilor succesive. S explicm codul din DrawHello. hDC = BeginPaint(hwnd, &paintStruct); BeginPaint ncearc s completeze variabila paintStruct i ca rspuns obine un context de dispozitiv care va trebui folosit de funciile din GDI. Ieirile grafice au nevoie de acest context de dispozitiv. GetClientRect(hwnd, &clientRect);
Se obin dimensiunile zonei client, completate n clientRect. Observai parametrii funciei: hwnd va indica pentru ce fereastr se dorete acest lucru. DPtoLP(hDC, (LPPOINT)&clientRect, 2); Coordonatele fizice sunt transformate n coordonate logice. Primul parametru, hDC, indic pentru ce context de dispozitiv se face acest lucru. DrawText(hDC, "Hello, World!", -1, &clientRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); Se afieaz n zona client, Hello, World!, folosind contextul de dispozitiv obiunut de BeginPaint. EndPaint(hwnd, &paintStruct); Se termin desenarea, i se distrug informaiile din paintStruct. La terminarea funciei, hDC se distruge, fiind local. n fapt dup EndPaint hDC-ul nu mai este valid. Procedura fereastr nu este nimic altceva dect o structura mare switch.
ReleaseCapture() = elibereaz capturarea mouse-ului. GetDC() = obine un context de dispozitiv pentru a desena n fereastr (zona client). ReleaseDC() = elibereaz contextul de dispozitiv obinut cu GetDC. #include <windows.h> void AddSegmentAtMessagePos(HDC hDC, HWND hwnd, BOOL bDraw) { DWORD dwPos; POINTS points; POINT point; dwPos = GetMessagePos(); points = MAKEPOINTS(dwPos); point.x = points.x; point.y = points.y; ScreenToClient(hwnd, &point); DPtoLP(hDC, &point, 1); if (bDraw) LineTo(hDC, point.x, point.y); else MoveToEx(hDC, point.x, point.y, NULL); } void DrawHello(HWND hwnd) { HDC hDC; MSG msg; if (GetCapture() != NULL) return; hDC = GetDC(hwnd); if (hDC != NULL) { SetCapture(hwnd); AddSegmentAtMessagePos(hDC, hwnd, FALSE); while(GetMessage(&msg, NULL, 0, 0)) { if (GetCapture() != hwnd) break; switch (msg.message) { case WM_MOUSEMOVE: AddSegmentAtMessagePos(hDC, hwnd, TRUE); break; case WM_LBUTTONUP: goto ExitLoop; default: DispatchMessage(&msg); } } ExitLoop: ReleaseCapture(); ReleaseDC(hwnd, hDC); } } LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_LBUTTONDOWN: DrawHello(hwnd);
break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR d3, int nCmdShow) { MSG msg; HWND hwnd; WNDCLASS wndClass; if (hPrevInstance == NULL) { memset(&wndClass, 0, sizeof(wndClass)); wndClass.style = CS_HREDRAW | CS_VREDRAW; wndClass.lpfnWndProc = WndProc; wndClass.hInstance = hInstance; wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wndClass.lpszClassName = "HELLO"; if (!RegisterClass(&wndClass)) return FALSE; } hwnd = CreateWindow("HELLO", "HELLO", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg); return msg.wParam; } Observaie. Mesajul WM_MOUSEMOVE poate fi tratat i n bucla de mesaje din WinMain, dar pentru a realiza aceeai funcionalitate codul i logica aplicaiei trebuiesc schimbate.
Concluzii
Fiecare aplicaie Windows este construit n jurul unei bucle de mesaje . O bucl de mesaje
face apeluri repetate la funciile GetMessage sau PeekMessage i regsete mesajele pe care le dispecereaz procedurilor fereastr prin funcia DispatchMessage. Procedurile fereastr sunt definite pentru clasele fereastr n momemntul cnd clasa fereastr a fost nregistrat prin RegisterClass. Mesajele adresate aplicaiei sunt tratate de procedura fereastr sau sunt trimise procedurii implicite DefWindowProc sau DefDlgProc n situaia cnd nu sunt tratate de procedura fereastr. Orice mesaj windows trebuie tratat, nu trebuie pierdut. Mesajele pot fi plasate sau trimise unei aplicaii. Mesajele plasate sunt depozitate n coada de unde sunt regsite cu GetMessage sau PeekMessage. Fa de un mesaj plasat, un mesaj trimis ( SendMessage) implic
imediat un apel al procedurii fereastr. Cu alte cuvinte nu se termin execuia funciei SendMessage pn cnd mesajul nu a fost tratat. O aplicaie poate avea mai multe bucle de mesaje.