Własne klasy obsługujące podstawowe kontrolki WinApi

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

Sporą wadą WinApi jest fakt, że obsługa kontrolek wymaga znajomości wielu funkcji obsługi okien oraz komunikatów i styli wpływających na wygląd tychże kontrolek. Nie ma tutaj również mowy o obiektowym tworzeniu kontrolek. Można jednak samemu napisać sobie klasy, które umożliwią łatwe obsłużenie tworzenia kontrolek, sterowania ich zachowaniem oraz wyglądem. Z tego właśnie powodu utworzyłem sobie mały zbiór klas, które umożliwiają mi dynamiczne tworzenie kontrolek oraz łatwy dostęp do opcji nimi sterujących oraz możliwość podpinania obiektów klas odpowiedzialnych za realizację zadań wywoływanych przez notyfikacje wysyłane przez daną kontrolkę do okna rodzica.

Oto lista klas do obsługi podstawowych kontrolek:

  • WndLabel - klasa odpowiedzialna za tworzenie i obsługę notyfikacji kontrolki static;
  • WndEdit - klasa odpowiedzialna za tworzenie i obsługę notyfikacji kontrolki edit;
  • WndButton - klasa odpowiedzialna za tworzenie i obsługę notyfikacji kontrolki button;
  • WndScrollBar - klasa odpowiedzialna za tworzenie i obsługę notyfikacji kontrolki scrollbar;
  • WndListBox - klasa odpowiedzialna za tworzenie i obsługę notyfikacji kontrolki listbox;
  • WndComboBox - klasa odpowiedzialna za tworzenie i obsługę notyfikacji kontrolki combobox;
  • WndTooltip - klasa odpowiedzialna za tworzenie i obsługę notyfikacji kontrolki tooltip służącej do wyświetlania podpowiedzi/opisów kontekstowych innych kontrolek.
Przykładowy widok dynamicznie utworzonych w WinApi kontrolek przy użyciu klas
Rys. 1
Przykładowy widok dynamicznie utworzonych w WinApi kontrolek przy użyciu klas

Cały kod poszczególnych klas wraz z przykładem ich zastosowania zamieściłem na stronie GitHub. Jedynie pokażę jak można tworzyć kontrolki za ich pomocą. Oto jak tworzone są kontrolki w komunikacie WM_CREATE:

Listing 1
  1. case WM_CREATE:
  2. {
  3. NONCLIENTMETRICS ncm;
  4. ncm.cbSize=sizeof(ncm);
  5. SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
  6. font = CreateFontIndirect(&ncm.lfStatusFont);
  7. myEdit = new WndEdit( // Create WndEdit control object
  8. "some edit stuff", // text to set in edit control
  9. ws::window::ws_child // control styles: as child window
  10. | ws::window::ws_visible // as visible window
  11. | ws::window::ws_hscrollbar // as window with horizontal scroll bar
  12. | ws::window::ws_vscrollbar // as window with vertical scroll bar
  13. | ws::edit::es_autohscroll // as edit control with auto horizontal scroll
  14. | ws::edit::es_autovscroll // as edit control with auto vertical scroll
  15. | ws::edit::es_multiline, // as multiline edit control
  16. 100, // x - position
  17. 0, // y - position
  18. 100, // width
  19. 50, // height
  20. hWnd, // handle to parent window
  21. (HMENU) 5000, // in this case id of control
  22. hInst, // handle to application instance
  23. NULL // pointer to some extra data stuff (in this cas NULL means no extra data stuff)
  24. );
  25. // set myEdit object control font
  26. myEdit->setFont(font);
  27. myScrollBar = new WndScrollBar( // create WndScrollBar object of control ScrollBar
  28. ws::window::ws_child| // Style of control: as child
  29. ws::window::ws_visible| // as visible
  30. ws::scrollbar::sbs_horizontal, // as hotizontal scroll bar
  31. 100, // x - position
  32. 50, // y - position
  33. 100, // width
  34. 20, // height
  35. hWnd, // parent window handle
  36. (HMENU) 5001, // in this case it is a id of control
  37. hInst, // handle to application instance
  38. NULL // pointer to some extra data stuff (in this cas NULL means no extra data stuff)
  39. );
  40. SCROLLINFO si; // structure describe setting of scroll bar control
  41. si.cbSize = sizeof(SCROLLINFO); // this parameter must be set
  42. si.fMask = SIF_ALL; // flag describing whitch of struct field will be used
  43. si.nMax = 110; // maximum value + nPage - 1
  44. si.nMin = 0; // minimum value
  45. si.nPage = 11; // page scrolling size
  46. si.nPos = 0; // current scroll bar pos
  47. si.nTrackPos = 0; // current track pos
  48. myScrollBar->setScrollInfo(&si, false); // set settings of scrollbar
  49. myScrollBar->setThumbtract(true); // this means that when user move control slider then value of nPos Scroll Bar is changed
  50. // add some notification command for myScrollBar object control
  51. myScrollBar->addNotification(WndScrollBar::notifications::wmscroll, new OnScrollChanged(myEdit, myScrollBar));
  52. myListBox = new WndListBox( // create WndListBox window object
  53. ws::window::ws_hscrollbar| // with styla: hotizontal scrollbar
  54. ws::window::ws_vscrollbar| // vertical scrollbar
  55. ws::window::ws_child| // as child window
  56. ws::window::ws_visible| // as visible widnow
  57. ws::listbox::lbs_notify| // with sending notification code
  58. ws::listbox::lbs_hasstrings,// with string data item
  59. 100, // x-position
  60. 70, // y-position
  61. 100, // control width
  62. 100, // control height
  63. hWnd, // parent window handle
  64. (HMENU) 5002, // in this case it is an window ID
  65. hInst, // application instance handle
  66. NULL // pointer to some extra data (in this case NULL - means no extra data)
  67. );
  68. // add items to list box
  69. myListBox->addTextItem("Polska");
  70. myListBox->addTextItem("Czechy");
  71. myListBox->addTextItem("Słowacja");
  72. myListBox->addTextItem("Litwa");
  73. myListBox->addTextItem("Łotwa");
  74. myListBox->addTextItem("Estonia");
  75. myListBox->addTextItem("Węgry");
  76. myListBox->addTextItem("Stany Zjednoczone Ameryki");
  77. // set myListBox font
  78. myListBox->setFont(font);
  79. // add some notifications stuff
  80. myListBox->addNotification(WndListBox::notifications::selchange, new OnListBoxSelChanged(myEdit, myListBox)); // notification command for selchange notify
  81. myListBox->addNotification(WndListBox::notifications::doubleclick, new OnListBoxDblClick(myEdit, myListBox)); // notification command for doubleclick notify
  82. myLabel = new WndLabel( // create WndLabel object of Static control
  83. "Label", // text to write in window
  84. ws::window::ws_child| // window style: as child
  85. ws::window::ws_visible| // as visible
  86. ws::label::ss_notify, // with sending notifications to parent window
  87. 100, // x - position
  88. 170, // y - position
  89. 100, // width
  90. 20, // height
  91. hWnd, // parent window handle
  92. (HMENU) 5003, // in this case id of cotrol
  93. hInst, // handle to application instance
  94. NULL // pointer to some extra data (in this case NULL - means no extra data)
  95. );
  96. // set myLabel font
  97. myLabel->setFont(font);
  98. // add notification command object to myLabel control
  99. myLabel->addNotification(WndLabel::notifications::clicked, new OnLabelClick(myLabel));
  100. myComboBox = new WndComboBox( // create WndComboBox class object of combobox control
  101. ws::window::ws_child| // with style: as child
  102. ws::window::ws_visible| // as visible
  103. ws::window::ws_vscrollbar| // with vertical scrollbar
  104. ws::combobox::cbs_hasstrings| // with string data for stored items
  105. ws::combobox::cbs_dropdown, // with drop down list
  106. 100, // x - position
  107. 190, // y - position
  108. 100, // width
  109. 100, // height (including drop down list height)
  110. hWnd, // handle to parent window
  111. (HMENU) 5004, // in this case control id
  112. hInst, // application instance handle
  113. NULL // pointer to some extra data (in this case NULL - means no extra data)
  114. );
  115. // add items to combo box
  116. myComboBox->addTextItem("Polska");
  117. myComboBox->addTextItem("Czechy");
  118. myComboBox->addTextItem("Słowacja");
  119. myComboBox->addTextItem("Litwa");
  120. myComboBox->addTextItem("Łotwa");
  121. myComboBox->addTextItem("Estonia");
  122. myComboBox->addTextItem("Węgry");
  123. myComboBox->addTextItem("Stany Zjednoczone Ameryki");
  124. myComboBox->setFont(font);
  125. myComboBox->addNotification(WndComboBox::notifications::selchange, new OnComboBoxSelChanged(myEdit, myComboBox));
  126. }
  127. break;

Ważnym elementem obsługi kontrolek w WinApinotyfikacje, czyli komunikaty pochodzące od danej kontrolki wysyłane do okna rodzica. Mechanizm podpinania jest bardzo prosty i przytoczę tutaj jeden przykładowy wycinek z listing-u 1:

Listing 2
  1. myComboBox->addNotification(WndComboBox::notifications::selchange, new OnComboBoxSelChanged(myEdit, myComboBox));

To co jest wykonywane w powyższym fragmencie kodu to podpinanie pod zdarzenie (notyfikację) typu selchange obiektu klasy OnComboBoxSelChanged. Klasa ta dziedziczy po specjalnie utworzonym interfejsie INotificationCommand, który dysponuje czysto wirtualną metodą notify. To ta metoda będzie wywoływana, gdy obiekt wyśle notyfikację do okna rodzica. Do obsługi więc notyfikacji konieczne jest utworzenie takiej klasy. Oto przykład:

Listing 3
  1. class OnComboBoxSelChanged : public INotificationCommand{
  2. public:
  3. WndEdit* edit;
  4. WndComboBox* combobox;
  5. OnComboBoxSelChanged(WndEdit* edit, WndComboBox* combobox) : edit(edit), combobox(combobox){}
  6. virtual void notify(){
  7. edit->setWindowText(combobox->getSelectedText());
  8. }
  9. };

Klasa OnComboBoxSelChanged przechowuje dane niezbędne do realizacji zadań wykonywanych w metodzie notify. Niestety samo podpięcie klasy nie wystarczy, trzeba jeszcze obsłużyć komunikat WM_COMMAND, gdzie lądują notyfikacje wysyłane przez okna potomne. Oto przykładowy kod:

Listing 4
  1. case WM_COMMAND:
  2. {
  3. UINT nc = HIWORD(wParam);
  4. UINT id = LOWORD(wParam);
  5. HWND ctrl = (HWND) lParam;
  6. if(myListBox->notify(ctrl, id, nc)) // doing notification stuff for myListBox control object
  7. break;
  8. if(myLabel->notify(ctrl, id, nc)) // doing notification stuff for myLabel control object
  9. break;
  10. if(myComboBox->notify(ctrl, id, nc)) // doing notification stuff for myComboBox control object
  11. break;
  12. }
  13. break;

Jak widać metoda notify wywołana w komunikacie WM_COMMAND wykonuje całą brudną robotę związaną z obsługą notyfikacji i zwraca wartość niezerową, gdy notyfikacja została obsłużona.

Strony powiązane
strony powiązane
  1. github.com/Obliczeniowo/WinApiControlsClass - repozytorium z całym kodem klas i przykładem ich użycia

Komentarze