Tworzenie własnego okna programu

Autor podstrony: Krzysztof Zajączkowski

Stronę tą wyświetlono już: 5048 razy

Kod programu

Na wcześniejszej stronie omówiony został sposób tworzenia nowego projektu o nazwie HelloWorld. Tym razem utworzony projekt będzie wykorzystywał własnoręcznie utworzone okno programu w celu wyświetlenia tego samego tekstu. Rozpocząć należy oczywiście od utworzenia projektu, tym razem niech jego nazwa będzie np. HelloWorld2. Projekt musi być pusty i należy dodać do niego plik winmain.cpp w sposób wcześniej już omawiany.

Oto kod prostego programu, którego jedynym celem będzie wyświetlania napisu Witaj świecie:

#include <windows.h> LRESULT CALLBACK hwndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){ static RECT wndSize; // zmienna statyczna przechowująca informacje o wymiarach okna switch(msg){ case WM_CREATE: // ten komunikat będzie obsłużony zawsze jako pierwszy { } break; case WM_DESTROY: // ten komunikat będzie obsłużony, gdy wciśniesz przycisk zamknięcia programu { PostQuitMessage(0); // kończy program } break; case WM_SIZE: { SetRect(&wndSize, // wskaźnik do struktury typu RECT 0, // zerowa pozycja lewego górnego narożnika okna 0, // zerowa pozycja prawego górnego narożnika okna LOWORD(lParam), // makro LOWORD wyciąga pierwszych 16 bitów z parametru lParam, które opisują szerokość okna HIWORD(lParam) // makro HIWORD wyciąga ostatnie 16 bitów z parametru lParam, które opisują wysokość okna ); // ustawia strukturę wndSize tak, aby przechowywała szerokość i wysokość okna } break; case WM_PAINT: { PAINTSTRUCT ps; // struktora potrzebna do rysowania HDC hdc = BeginPaint(hWnd, &ps); // tworzenie kontekstu urządzenia HDC SetTextColor(hdc,RGB(255,255,255)); // ustawienie koloru tekstu SetBkMode(hdc, TRANSPARENT); // ustawienie przezroczystości tła tekstu DrawText(hdc, // kontekst urządzenia L"Witaj świecie", // tekst do wyświetlenia -1, // to powinna być długość ciągu znaków, które będą rysowane, jednakże w tym przypadku można podać -1 a program sam wyliczy tę wartość &wndSize, // struktura zawierająca rozmiar okna DT_CENTER | DT_VCENTER | DT_SINGLELINE // flagi trybów rysowania: text centralnie w poziomie; text centralnie w pionie; pojedyńcza linia tekstu (konieczne aby DT_VCENTER działało) ); // funkcja rysująca tekst EndPaint(hWnd, &ps); // kończenie rysowania } break; } return DefWindowProc(hWnd, msg, wParam, lParam); } int WINAPI WinMain(HINSTANCE hInst, HINSTANCE , LPSTR str, int ){ WNDCLASS wnd; wnd.cbClsExtra = NULL; // ten parametr powinien być ustawiony na null (powinien on zawierać informacje o rozmiarze dodatkowych danych jakie będą przechowywane dla danej klasy okna) wnd.cbWndExtra = NULL; // ten parametr powinien być ustawiony na null (powinien on zawierać informacje o rozmiarze dodatkowych danych jakie będą przechowywane dla danego egzemplarza okna) wnd.hbrBackground = CreateSolidBrush(RGB(0,0,0)); // to będzie tło okna wnd.hCursor = LoadCursor(NULL, IDC_ARROW); // ładowanie standardowego kursora wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION); // ładowanie standardowej ikonki aplikacji wnd.hInstance = hInst; // uchwyt instancji programu wnd.lpfnWndProc = hwndProc; // wskaźnik do funkcji będącej procedurą okna wnd.lpszClassName = L"Witaj świecie"; // nazwa klasy okna wnd.lpszMenuName = NULL; // tutaj powinno być menu, ale tym razem nie będzie żadnego menu więc NULL wnd.style = CS_VREDRAW|CS_HREDRAW; // opcje wyświetlania okna CS_VREDRAW i CS_HREDRAW oznaczają odświerzanie okna w poziomie i pionie if(!RegisterClass(&wnd)){ // jeżeli nie udało się zarejestrować klassy okna MessageBox(NULL,L"Wzięło się i nie zarejestrowało", L"Błąd", MB_OK); // to płacz, że coś się stało return 0; // i zwracaj zero } HWND hWnd = CreateWindow(L"Witaj świecie", // nazwa klasy okna L"Witaj świecie", // tekst belki tytułowej okna WS_OVERLAPPEDWINDOW, // styl okna (ten oznacza z belką tytułową, przyciskami minimalizacji, maksymalizacji i zwijania oraz z ramką CW_USEDEFAULT, // pozycja x (CS_USEDEFAULT oznacza domyślne) CW_USEDEFAULT, // pozycja y (CS_USEDEFAULT oznacza domyślne) CW_USEDEFAULT, // szerokość (CS_USEDEFAULT oznacza domyślne) CW_USEDEFAULT, // wysokość (CS_USEDEFAULT oznacza domyślne) NULL, // okno rodzica (tutaj nie będzie takiego więc NULL) NULL, // wskaźnik do menu (też nie będzie więc NULL) hInst, // uchwyt instancji programu NULL // wskaźnik do dodatkowych danych ); ShowWindow(hWnd, SW_NORMAL); // wyświetlania okna i jego tryb UpdateWindow(hWnd); // wymuszenie pierwszego odświerzenia okna MSG msg; // struktura komunikatów // tutaj jest pętla komunikatów while(GetMessage(&msg, 0,0,0)){ // dopóki nie otrzymano komunikatu == 0 TranslateMessage(&msg); // tłumacz komunikat DispatchMessage(&msg); // rozpakuj komunikat } return 0; }

W powyższym kodzie rejestracja klasy okna odbywa się za pomocą funkcji RegisterClass, która przyjmuje jako jedyny parametr wskaźnik do struktury WNDCLASS. Przeznaczenie wszystkich pól struktury WNDCLASS zostało wyjaśnione w kodzie programu. Tworzenie okna programu oraz jego uchwytu HWND odbywa się za pomocą funkcji CreateWindow, której parametry również opisałem w kodzie. Dalej są funkcje odpowiedzialne za wyświetlenie okna ShowWindow oraz pierwsze jego odświeżenie UpdateWindow. Następnie potrzebna jest struktura do przetwarzania komunikatów oraz funkcja GetMessage do ich przechwytywania. Tłumaczenie i rozpakowywanie otrzymanego komunikatu odbywa się odpowiednio za pomocą funkcji TranslateMessage i DispatchMessage.

W funkcji procedury okna hwndProc warto przyjrzeć się dwóm komunikatom WM_SIZE oraz WM_PAINT. Pierwszy z nich odpowiedzialny jest za pozyskiwanie informacji o rozmiarze okna, które z kolei przechowywane są w zmiennej statycznej typu RECT (skrót od rectangle - prostokąt). Do wypełnienia tej struktury wykorzystana została funkcja SetRect. Co ciekawe w parametrze lParam funkcji hwndProc zawarta została informacja na temat rozmiaru obszaru okna. Okazuje się bowiem, że pierwszych 16 bitów parametru lParam zawiera informację o szerokości okna natomiast następne 16 bitów zawiera informacje o wysokości okna. Do wyciągnięcia tych informacji użyto makr LOWORD (skrót od low word - niższe słowo) oraz HIWORD (skrót od hight word - wyższe słowo).

Komunikat WM_PAINT wykorzystuje w swym wnętrzu strukturę typu PAINTSTRUCT oraz dwie kluczowe funkcje BeginPaint - dzięki której pozyskiwany jest kontekst urządzenia HDC oraz na końcu EndPaint. Ważnym jest aby wiedzieć, że struktury PAINSTRUCT oraz funkcji BeginPaint i EndPaint można używać tylko i wyłącznie w komunikacie WM_PAINT i nigdzie indziej.

Makra, funkcje i struktury użyte w kodzie

Poniżej zamieszczam spis nowo użytych makr występujących w kodzie programu:

Lista funkcji:

Lista struktur:

Propozycje książek