Tworzenie własnego okna programu

Stronę tą wyświetlono już: 286 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:

Listing 1
  1. #include <windows.h>
  2. LRESULT CALLBACK hwndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
  3. static RECT wndSize; // zmienna statyczna przechowująca informacje o wymiarach okna
  4. switch(msg){
  5. case WM_CREATE: // ten komunikat będzie obsłużony zawsze jako pierwszy
  6. {
  7. }
  8. break;
  9. case WM_DESTROY: // ten komunikat będzie obsłużony, gdy wciśniesz przycisk zamknięcia programu
  10. {
  11. PostQuitMessage(0); // kończy program
  12. }
  13. break;
  14. case WM_SIZE:
  15. {
  16. SetRect(&wndSize, // wskaźnik do struktury typu RECT
  17. 0, // zerowa pozycja lewego górnego narożnika okna
  18. 0, // zerowa pozycja prawego górnego narożnika okna
  19. LOWORD(lParam), // makro LOWORD wyciąga pierwszych 16 bitów z parametru lParam, które opisują szerokość okna
  20. HIWORD(lParam) // makro HIWORD wyciąga ostatnie 16 bitów z parametru lParam, które opisują wysokość okna
  21. ); // ustawia strukturę wndSize tak, aby przechowywała szerokość i wysokość okna
  22. }
  23. break;
  24. case WM_PAINT:
  25. {
  26. PAINTSTRUCT ps; // struktora potrzebna do rysowania
  27. HDC hdc = BeginPaint(hWnd, &ps); // tworzenie kontekstu urządzenia HDC
  28. SetTextColor(hdc,RGB(255,255,255)); // ustawienie koloru tekstu
  29. SetBkMode(hdc, TRANSPARENT); // ustawienie przezroczystości tła tekstu
  30. DrawText(hdc, // kontekst urządzenia
  31. L"Witaj świecie", // tekst do wyświetlenia
  32. -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ść
  33. &wndSize, // struktura zawierająca rozmiar okna
  34. 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)
  35. ); // funkcja rysująca tekst
  36. EndPaint(hWnd, &ps); // kończenie rysowania
  37. }
  38. break;
  39. }
  40. return DefWindowProc(hWnd, msg, wParam, lParam);
  41. }
  42. int WINAPI WinMain(HINSTANCE hInst, HINSTANCE , LPSTR str, int ){
  43. WNDCLASS wnd;
  44. 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)
  45. 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)
  46. wnd.hbrBackground = CreateSolidBrush(RGB(0,0,0)); // to będzie tło okna
  47. wnd.hCursor = LoadCursor(NULL, IDC_ARROW); // ładowanie standardowego kursora
  48. wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION); // ładowanie standardowej ikonki aplikacji
  49. wnd.hInstance = hInst; // uchwyt instancji programu
  50. wnd.lpfnWndProc = hwndProc; // wskaźnik do funkcji będącej procedurą okna
  51. wnd.lpszClassName = L"Witaj świecie"; // nazwa klasy okna
  52. wnd.lpszMenuName = NULL; // tutaj powinno być menu, ale tym razem nie będzie żadnego menu więc NULL
  53. wnd.style = CS_VREDRAW|CS_HREDRAW; // opcje wyświetlania okna CS_VREDRAW i CS_HREDRAW oznaczają odświerzanie okna w poziomie i pionie
  54. if(!RegisterClass(&wnd)){ // jeżeli nie udało się zarejestrować klassy okna
  55. MessageBox(NULL,L"Wzięło się i nie zarejestrowało", L"Błąd", MB_OK); // to płacz, że coś się stało
  56. return 0; // i zwracaj zero
  57. }
  58. HWND hWnd = CreateWindow(L"Witaj świecie", // nazwa klasy okna
  59. L"Witaj świecie", // tekst belki tytułowej okna
  60. WS_OVERLAPPEDWINDOW, // styl okna (ten oznacza z belką tytułową, przyciskami minimalizacji, maksymalizacji i zwijania oraz z ramką
  61. CW_USEDEFAULT, // pozycja x (CS_USEDEFAULT oznacza domyślne)
  62. CW_USEDEFAULT, // pozycja y (CS_USEDEFAULT oznacza domyślne)
  63. CW_USEDEFAULT, // szerokość (CS_USEDEFAULT oznacza domyślne)
  64. CW_USEDEFAULT, // wysokość (CS_USEDEFAULT oznacza domyślne)
  65. NULL, // okno rodzica (tutaj nie będzie takiego więc NULL)
  66. NULL, // wskaźnik do menu (też nie będzie więc NULL)
  67. hInst, // uchwyt instancji programu
  68. NULL // wskaźnik do dodatkowych danych
  69. );
  70. ShowWindow(hWnd, SW_NORMAL); // wyświetlania okna i jego tryb
  71. UpdateWindow(hWnd); // wymuszenie pierwszego odświerzenia okna
  72. MSG msg; // struktura komunikatów
  73. // tutaj jest pętla komunikatów
  74. while(GetMessage(&msg, 0,0,0)){ // dopóki nie otrzymano komunikatu == 0
  75. TranslateMessage(&msg); // tłumacz komunikat
  76. DispatchMessage(&msg); // rozpakuj komunikat
  77. }
  78. return 0;
  79. }

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:

  • LOWORD - wyciąga najniższych 16-bitów z zmiennej 32-bitowej;
  • HIWORD - wyciąga ostatnich 16-bitów z zmiennej 32-bitowej;
  • RGB - makro tworzące zmienną 24-bitową typu COLORREF opisującą kolor w systemie rgb (czerwony, zielony, niebieski).

Lista funkcji:

  • BeginPaint - funkcja używana do pozyskiwania kontekstu urządzenia HDC w komunikacie WM_PAINT. Ta funkcja jest ściśle powiązana z funkcją EndPaint oraz z strukturą PAINTSTRUCT;
  • CreateSolidBrush - funkcja używana do pozyskiwania uchwytu wypełnienia o określonym kolorze. Ta funkcja jest ściśle powiązana z typem COLORREF oraz makrem RGB;
  • CreateWindow - funkcja używana do utworzenia nowego uchwytu okna o określonej nazwie klasy okna, która z kolei powiązana jest ściśle z funkcją RegisterClass oraz strukturą WNDCLASS;
  • DefWindowProc - przekazuje nieobsłużone komunikaty dalej;
  • DispatchMessage - rozpakowuje komunikaty;
  • DrawText - wyświetla tekst rozmieszczając go w określonym prostokątnym obszarze;
  • EndPaint - funkcja używana do zwolnienia kontekstu urządzenia HDC w komunikacie WM_PAINT. Ta funkcja jest ściśle powiązana z funkcją BeginPaint oraz z strukturą PAINTSTRUCT;
  • GetMessage - przechwytuje komunikaty;
  • LoadCursor - ładuje kursor (w tym projekcie domyślny);
  • LoadIcon - ładuje ikonę (w tym projekcie domyślną);
  • PostQuitMessage - funkcja kończąca żywot programu;
  • RegisterClass - funkcja umożliwiająca rejestrowanie klasy okna. Funkcja jest ściśle powiązana z strukturą WNDCLASS;
  • SetBkMode - ustawia tryb rysowania tekstu z tłem lub bez tła dla danego kontekstu urządzenia HDC;
  • SetRect - funkcja ustawiająca pola struktury typu RECT;
  • SetTextColor - funkcja ustawiająca kolor, jakim tekst będzie rysowany w danym kontekście urządzenia HDC;
  • ShowWindow - funkcja wyświetla okno w określonym trybie (zminimalizowane, zmaksymalizowane ...);
  • TranslateMessage - tłumaczy komunikaty;
  • UpdateWindow - funkcja odświeża okno.

Lista struktur:

  • MSG - struktura związana z pętlą komunikatów i przechwytywaniem komunikatów;
  • PAINTSTRUCT - struktura związana z pozyskiwaniem kontekstu urządzenia w komunikacie WM_PAINT;
  • WNDCLASS - struktura związana z rejestracją nowej klasy okna;

Komentarze