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

Autor podstrony: Krzysztof Zajączkowski

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

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:

case WM_CREATE: { NONCLIENTMETRICS ncm; ncm.cbSize=sizeof(ncm); SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0); font = CreateFontIndirect(&ncm.lfStatusFont); myEdit = new WndEdit( // Create WndEdit control object "some edit stuff", // text to set in edit control ws::window::ws_child // control styles: as child window | ws::window::ws_visible // as visible window | ws::window::ws_hscrollbar // as window with horizontal scroll bar | ws::window::ws_vscrollbar // as window with vertical scroll bar | ws::edit::es_autohscroll // as edit control with auto horizontal scroll | ws::edit::es_autovscroll // as edit control with auto vertical scroll | ws::edit::es_multiline, // as multiline edit control 100, // x - position 0, // y - position 100, // width 50, // height hWnd, // handle to parent window (HMENU) 5000, // in this case id of control hInst, // handle to application instance NULL // pointer to some extra data stuff (in this cas NULL means no extra data stuff) ); // set myEdit object control font myEdit->setFont(font); myScrollBar = new WndScrollBar( // create WndScrollBar object of control ScrollBar ws::window::ws_child| // Style of control: as child ws::window::ws_visible| // as visible ws::scrollbar::sbs_horizontal, // as hotizontal scroll bar 100, // x - position 50, // y - position 100, // width 20, // height hWnd, // parent window handle (HMENU) 5001, // in this case it is a id of control hInst, // handle to application instance NULL // pointer to some extra data stuff (in this cas NULL means no extra data stuff) ); SCROLLINFO si; // structure describe setting of scroll bar control si.cbSize = sizeof(SCROLLINFO); // this parameter must be set si.fMask = SIF_ALL; // flag describing whitch of struct field will be used si.nMax = 110; // maximum value + nPage - 1 si.nMin = 0; // minimum value si.nPage = 11; // page scrolling size si.nPos = 0; // current scroll bar pos si.nTrackPos = 0; // current track pos myScrollBar->setScrollInfo(&si, false); // set settings of scrollbar myScrollBar->setThumbtract(true); // this means that when user move control slider then value of nPos Scroll Bar is changed // add some notification command for myScrollBar object control myScrollBar->addNotification(WndScrollBar::notifications::wmscroll, new OnScrollChanged(myEdit, myScrollBar)); myListBox = new WndListBox( // create WndListBox window object ws::window::ws_hscrollbar| // with styla: hotizontal scrollbar ws::window::ws_vscrollbar| // vertical scrollbar ws::window::ws_child| // as child window ws::window::ws_visible| // as visible widnow ws::listbox::lbs_notify| // with sending notification code ws::listbox::lbs_hasstrings,// with string data item 100, // x-position 70, // y-position 100, // control width 100, // control height hWnd, // parent window handle (HMENU) 5002, // in this case it is an window ID hInst, // application instance handle NULL // pointer to some extra data (in this case NULL - means no extra data) ); // add items to list box myListBox->addTextItem("Polska"); myListBox->addTextItem("Czechy"); myListBox->addTextItem("Słowacja"); myListBox->addTextItem("Litwa"); myListBox->addTextItem("Łotwa"); myListBox->addTextItem("Estonia"); myListBox->addTextItem("Węgry"); myListBox->addTextItem("Stany Zjednoczone Ameryki"); // set myListBox font myListBox->setFont(font); // add some notifications stuff myListBox->addNotification(WndListBox::notifications::selchange, new OnListBoxSelChanged(myEdit, myListBox)); // notification command for selchange notify myListBox->addNotification(WndListBox::notifications::doubleclick, new OnListBoxDblClick(myEdit, myListBox)); // notification command for doubleclick notify myLabel = new WndLabel( // create WndLabel object of Static control "Label", // text to write in window ws::window::ws_child| // window style: as child ws::window::ws_visible| // as visible ws::label::ss_notify, // with sending notifications to parent window 100, // x - position 170, // y - position 100, // width 20, // height hWnd, // parent window handle (HMENU) 5003, // in this case id of cotrol hInst, // handle to application instance NULL // pointer to some extra data (in this case NULL - means no extra data) ); // set myLabel font myLabel->setFont(font); // add notification command object to myLabel control myLabel->addNotification(WndLabel::notifications::clicked, new OnLabelClick(myLabel)); myComboBox = new WndComboBox( // create WndComboBox class object of combobox control ws::window::ws_child| // with style: as child ws::window::ws_visible| // as visible ws::window::ws_vscrollbar| // with vertical scrollbar ws::combobox::cbs_hasstrings| // with string data for stored items ws::combobox::cbs_dropdown, // with drop down list 100, // x - position 190, // y - position 100, // width 100, // height (including drop down list height) hWnd, // handle to parent window (HMENU) 5004, // in this case control id hInst, // application instance handle NULL // pointer to some extra data (in this case NULL - means no extra data) ); // add items to combo box myComboBox->addTextItem("Polska"); myComboBox->addTextItem("Czechy"); myComboBox->addTextItem("Słowacja"); myComboBox->addTextItem("Litwa"); myComboBox->addTextItem("Łotwa"); myComboBox->addTextItem("Estonia"); myComboBox->addTextItem("Węgry"); myComboBox->addTextItem("Stany Zjednoczone Ameryki"); myComboBox->setFont(font); myComboBox->addNotification(WndComboBox::notifications::selchange, new OnComboBoxSelChanged(myEdit, myComboBox)); } 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:

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:

class OnComboBoxSelChanged : public INotificationCommand{ public: WndEdit* edit; WndComboBox* combobox; OnComboBoxSelChanged(WndEdit* edit, WndComboBox* combobox) : edit(edit), combobox(combobox){} virtual void notify(){ edit->setWindowText(combobox->getSelectedText()); } };

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:

case WM_COMMAND: { UINT nc = HIWORD(wParam); UINT id = LOWORD(wParam); HWND ctrl = (HWND) lParam; if(myListBox->notify(ctrl, id, nc)) // doing notification stuff for myListBox control object break; if(myLabel->notify(ctrl, id, nc)) // doing notification stuff for myLabel control object break; if(myComboBox->notify(ctrl, id, nc)) // doing notification stuff for myComboBox control object break; } 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
Propozycje książek