Tworzenie własnych okien dialogowych

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

Graficzny interfejs tworzenia szablonów własnych okien dialogowych

Utwórzmy nowy projekt o nazwie PrzeliczanieJednostek, do projektu dodać należy plik wndmain.cpp oraz plik zasobów (w sposób już omawiany wcześniej) poprzez dodanie tylko i wyłącznie jednego elementu Dialog, by oczom naszym ukazał się widok z poniższego rysunku.

Podstawowy szablon okna dialogowego
Rys. 1
Podstawowy szablon okna dialogowego

Wiele osób zarzuca WinApi brak możliwości ręcznego tworzenia interfejsu programu, nie jest to (jak widać) jednak do końca prawdziwym stwierdzeniem. Podstawowe okienko nie ma zbyt wiele elementów, ot dwa przyciski wewnątrz formy (okienka, w którym znajdują się wszystkie kontrolki). Oczywiście ten stan rzeczy można łatwo zmienić, albowiem okazuje się, że wystarczy wcisnąć kombinację klawiszy Ctrl+Alt+X lub (jak kto woli) wybrać z menu View→Toolbox, aby naszym oczom ukazało się jak za dotknięciem czarodziejskiej różdżki okienko z poniższego rysunku.

Okno narzędziowe Toolbox
Rys. 2
Okno narzędziowe Toolbox

Przez grzeczność i szacunek do czytelnika oraz (co tu dużo pisać) szacunek do samego siebie, nie będę tutaj wymieniał i opisywał wszystkich elementów dostępnych na liście okna Toolbox. Jest tych elementów sporo, a jeżeli ktoś chce się nauczyć ich wszystkich to może to zrobić już samodzielnie na własną rękę. Ja postaram się wykorzystać kilka z tych elementów do stworzenia bardzo prostego programu, który będzie przeliczał jednostki długości.

Należy dodać do szablonu okna elementy widoczne na poniższym rysunku, którymi są:

  • cztery kontrolki Static text, które będą stanowiły opis poszczególnych kontrolek pod nimi zawartych;
  • dwie kontrolki Edit control, które będą odpowiedzialne: jedna za wprowadzanie danych; druga za wyświetlanie wyniku przeliczania;
  • dwie kontrolki Combo Box, które będą umożliwiały wybranie jednostek przeliczanych wartości.
Widok okna dialogowego z dodanymi elementami
Rys. 3
Widok okna dialogowego z dodanymi elementami.

Przydałoby się nadać jakieś konkretne nazwy kontrolkom Static text, tak aby opisywały one poprawnie poszczególne kontrolki pod nimi się znajdujące. Czym prędzej więc zaznaczyć należy pierwszą kontrolkę a następnie wcisnąć kombinację klawiszy Alt+Enter lub (jak kto woli) View→Other windows→Properties window, by ukazało się okno Properties. W oknie tym należy zmienić tekst wpisany w polu Caption z Static na Wartość przeliczana:. Dla kolejnej kontrolki należy zmienić to samo pole na Wartość przeliczona:, dla kolejnego pola: Jednostka początkowa: oraz dla ostatniego Jednostka końcowa:. Dodatkowo w obu tych kontrolkach należy zmienić wartość pola Sort z true na false.

Dla elementów typu Edit control warto też zmienić nazwę zawartą w polu ID, dla pierwszego od lewej z ID_EDIT1 na ID_PRZELICZANE, oraz dla drugiego z ID_EDIT2 na ID_PRZELICZONE.

Dla elementów typu Edit Box warto też zmienić nazwę zawartą w polu ID, dla pierwszego od lewej z ID_EDITBOX1 na ID_JEDN_PRZELICZANE, oraz dla drugiego z ID_EDITBOX2 na ID_JEDN_PRZELICZONE.

Na koniec warto jeszcze zaznaczyć samą formę i zmienić jej właściwości w oknie Properties w polu Caption z Dialog na Przeliczanie jednostek długości oraz pole ID z IDD_DIALOG1 na IDD_WINDOW.

Na koniec pozbądźmy się w perfidny sposób przycisku Cancel, który nie będzie nam potrzebny do szczęścia oraz zmieńmy właściwość przycisku OK na Przelicz w polu Caption okna Properties.

Po wszystkich tych zabiegach szablon okna dialogowego powinien wyglądać tak, jak na poniższym rysunku.

Okno dialogowe po zmianach oraz pasek narzędziowy umożliwiający sterowanie położeniem elementów okna.
Rys. 4
Okno dialogowe po zmianach oraz pasek narzędziowy umożliwiający sterowanie położeniem elementów okna: 1 - włączanie podglądu okna dialogowego; 2 - przyciski umożliwiające wyrównywanie elementów; 3 - przyciski związane z wyrównywaniem względem okna; 4 - wyrównywanie szerokości lub wysokości zaznaczonej grupy kontrolek; 5 - przełącza widok w tryb siatki.

Kod programu

Nadszedł najwyższy czas i najwyższa pora, aby napisać kod programu, który omówię kolejno w komentarzach:

Listing 1
  1. #include <windows.h>
  2. #include <stdio.h> // biblioteka potrzebna do zamiany tekstu na liczbę i na odwrót
  3. #include "resource.h" // plik zasobów
  4. BOOL CALLBACK DlgProcPrzeliczanie(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam){ // procedura okna dialogowego
  5. static HWND edit_in; // uchwyt kontrolki statycznej edit, do której użytkownik powinien wpisać wartość przeliczaną
  6. static HWND edit_out; // uchwyt kontrolki statycznej edit, do której program będzie wypisywał wynik przeliczenia
  7. static HWND box_units_in; // kontrolka wyboru jednostki wejściowej
  8. static HWND box_units_out; // kontrolka wyboru jednostki wyjściowej
  9. static double units_calc[] = {1, 10e-6, 10e-9, 10e-10,0.94605e16, 3.0857e16, 1.496311e11, 1.852e3, 1.852e3, 2.54e-2,0.37594e-3, 0.451128e-2,1.804511e-2}; // tablica przeliczników (kolejność odpowiada kolejności wstawionych elementów kontrolek COMBOBOX
  10. switch(msg){ // przetwarzanie komunikatów
  11. case WM_INITDIALOG: // inicjalizacja okna dialogowego
  12. {
  13. edit_in = GetDlgItem(hDlg, ID_PRZELICZANE); // funkcją GetDlgItem mogę pobrać uchwyt okna potomnego o podanym identyfikatorze
  14. edit_out = GetDlgItem(hDlg, ID_PRZELICZONE);
  15. box_units_in = GetDlgItem(hDlg, ID_JEDN_PRZELICZANE);
  16. box_units_out = GetDlgItem(hDlg, ID_JEDN_PRZELICZONE);
  17. // =========== DODAWANIE ELEMENTÓW DO PIERWSZEGO COMBOBOXA ========================
  18. SendMessage(box_units_in, CB_ADDSTRING, 0, (LPARAM) L"metr [m]");
  19. SendMessage(box_units_in, CB_ADDSTRING, 0, (LPARAM) L"mikron [μ]");
  20. SendMessage(box_units_in, CB_ADDSTRING, 0, (LPARAM) L"milimikron [mμ]");
  21. SendMessage(box_units_in, CB_ADDSTRING, 0, (LPARAM) L"angstrem [Å]");
  22. SendMessage(box_units_in, CB_ADDSTRING, 0, (LPARAM) L"rok świetlny [-]");
  23. SendMessage(box_units_in, CB_ADDSTRING, 0, (LPARAM) L"parsek [pc]");
  24. SendMessage(box_units_in, CB_ADDSTRING, 0, (LPARAM) L"jednostka astronomiczna długości [AU/UA]");
  25. SendMessage(box_units_in, CB_ADDSTRING, 0, (LPARAM) L"mila morska [-]");
  26. SendMessage(box_units_in, CB_ADDSTRING, 0, (LPARAM) L"kabel [-]");
  27. SendMessage(box_units_in, CB_ADDSTRING, 0, (LPARAM) L"cal [in]");
  28. SendMessage(box_units_in, CB_ADDSTRING, 0, (LPARAM) L"punkt typograficzny [-]");
  29. SendMessage(box_units_in, CB_ADDSTRING, 0, (LPARAM) L"cycero [-]");
  30. SendMessage(box_units_in, CB_ADDSTRING, 0, (LPARAM) L"kwadrat [-]");
  31. // ============== USTAWIENIE POCZĄTKOWEGO POLA ZAZNACZENIA KONTROLKI COMBOBOX ================
  32. SendMessage(box_units_in, CB_SETCURSEL, 0, 0);
  33. // =========== DODAWANIE ELEMENTÓW DO DRUGIEGO COMBOBOXA ========================
  34. SendMessage(box_units_out, CB_ADDSTRING, 0, (LPARAM) L"metr [m]");
  35. SendMessage(box_units_out, CB_ADDSTRING, 0, (LPARAM) L"mikron [μ]");
  36. SendMessage(box_units_out, CB_ADDSTRING, 0, (LPARAM) L"milimikron [mμ]");
  37. SendMessage(box_units_out, CB_ADDSTRING, 0, (LPARAM) L"angstrem [Å]");
  38. SendMessage(box_units_out, CB_ADDSTRING, 0, (LPARAM) L"rok świetlny [-]");
  39. SendMessage(box_units_out, CB_ADDSTRING, 0, (LPARAM) L"parsek [pc]");
  40. SendMessage(box_units_out, CB_ADDSTRING, 0, (LPARAM) L"jednostka astronomiczna długości [AU/UA]");
  41. SendMessage(box_units_out, CB_ADDSTRING, 0, (LPARAM) L"mila morska [-]");
  42. SendMessage(box_units_out, CB_ADDSTRING, 0, (LPARAM) L"kabel [-]");
  43. SendMessage(box_units_out, CB_ADDSTRING, 0, (LPARAM) L"cal [in]");
  44. SendMessage(box_units_out, CB_ADDSTRING, 0, (LPARAM) L"punkt typograficzny [-]");
  45. SendMessage(box_units_out, CB_ADDSTRING, 0, (LPARAM) L"cycero [-]");
  46. SendMessage(box_units_out, CB_ADDSTRING, 0, (LPARAM) L"kwadrat [-]");
  47. // ============== USTAWIENIE POCZĄTKOWEGO POLA ZAZNACZENIA KONTROLKI COMBOBOX ================
  48. SendMessage(box_units_out, CB_SETCURSEL, 0, 0);
  49. return FALSE;
  50. }
  51. case WM_COMMAND: // przetwarzanie komunikatów pochodzących od okien potomnych
  52. {
  53. switch(LOWORD(wParam)){
  54. case IDOK: // gdy przycisk Przelicz wysyła komunikat
  55. {
  56. if(HIWORD(wParam) == BN_CLICKED){ // jak użytkownik kliknął przycisk to
  57. wchar_t val[100]; // bufor
  58. GetWindowText(edit_in, val, 100); // pobieram tekst okna kontrolki edit_in
  59. double d_val = 0; // bufor na liczbę
  60. if(wcslen(val)){ // jak dłigość tekstu jest różna od zera to
  61. d_val = _wtof(val); // zamieniaj na double
  62. int in = SendMessage(box_units_in, CB_GETCURSEL, 0, 0); // pobieram indeks jednostki wejściowej
  63. int out = SendMessage(box_units_out, CB_GETCURSEL, 0, 0); // pobieram indeks jednostki wyjściowej
  64. d_val *= units_calc[in] / units_calc[out]; // przeliczanko
  65. swprintf_s(val,L"%e", d_val); // zamiana z double na tekst
  66. SetWindowText(edit_out, val); // ustawienie tekstu w oknie edit_out
  67. }else{
  68. MessageBox(NULL,L"Musisz coś wpisać", L"Błąd",MB_OK); // jak w oknie edit_in nie ma tekstu to trzeba powiadomić o tym użytkownika
  69. }
  70. }
  71. return FALSE; // zwracam fałsz
  72. }
  73. case IDCANCEL: // gdy przycisk zamykania okna zostanie wciśnięty to
  74. {
  75. EndDialog(hDlg, TRUE); // kończ żywot okna dialogowego
  76. return TRUE; // zwracaj prawdę
  77. }
  78. break;
  79. }
  80. }
  81. break;
  82. }
  83. return FALSE; // zwracaj fałsz
  84. }
  85. int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR , int ){
  86. // ================== OKNO DIALOGOWE ===================
  87. DialogBox(
  88. hInst, // uchyt instancji programu
  89. MAKEINTRESOURCE(IDD_WINDOW), // pobieranie identyfikatora zasobu zawierającego szablon okna dialogowego
  90. NULL, // to powinien być uchwyt okna rodzica, ale to okno nie ma rodzica i dlatego NULL
  91. DlgProcPrzeliczanie); // wskaźnik do procedury okna dialogowego
  92. return 0; // i zwracamy zero
  93. }

Użyte po raz pierwszy w kodzie funkcje

Oto lista funkcji, które zostały użyte po raz pierwszy w kodzie programu:

  • GetDlgItem - funkcja umożliwiająca pobranie uchwytu okna potomnego okna dialogowego;
  • wcslen - długość tekstu zawartego w zmiennej typu wchar_t*;
  • _wtof - funkcja zamienia tekst zawarty w zmiennej typu wchar_t* na liczbę typu double;
  • swprintf_s - funkcja zamieniająca a zarazem formatująca zmienną typu double na ciąg znaków wchar_t*;
  • EndDialog - kończy działanie okna dialogowego;
  • DialogBox - wywołuje okno dialogowe

Komentarze