Kontrolka typu toolbar
Stronę tą wyświetlono już: 1626 razy
Wstęp
Kontrolka typu toolbar jest jedną z bardziej przydatnych kontrolek i służy ona do wyświetlania grup przycisków, które mogą być z sobą powiązane. Na tej stronie więc poświęcę nieco uwagi tworzeniu własnej kontrolki tego typu. W tym celu utworzyć należy nowy czysty projekt o nazwie Rysowanie, a to dlatego, że tworzyć będziemy program rysujący różne elementy w obszarze okna programu. Podstawą stworzenia takiego programu będzie kontrolka typu toolbar, która umożliwi przełączanie się pomiędzy trybami rysowania.
Toolbar - oznacza w tłumaczeniu na nasz język: pasek narzędziowy, tak więc ta kontrolka będzie wyświetlała różne narzędzia związane z realizacją zadań programu.
Dodawanie bitmapy do zasobów programu
Zanim przystąpię do pisania samego programu, konieczne jest najpierw dodanie do projektu pliku zasobów .rc wraz z bitmapą, której właściwości powinny być następujące:
- szerokość - 192 px;
- wysokość - 48 px;
- głębia kolorów - 8 bitowa;
Bitmapa ta powinna wyglądać mniej więcej tak jak na poniższym rysunku, i zostanie ona użyta przy tworzeniu paska narzędziowego.

Wszystkie właściwości bitmapy można zmienić w oknie Properties, które można wyświetlić za pomocą kombinacji klawiszy ctrl+enter lub z menu Viwe→Others Windows→Properties Window. W tym samym oknie należy zmienić wartość pola ID z domyślnej wartości na IDB_TB_BITMAP, ale najpierw konieczne jest zaznaczenie elementu dodanej bitmapy na liście zasobów znajdującej się w oknie Resource View - Rysowanie, które z kolei można wyświetlić wciskając kombinację klawiszy ctrl+shift+e lub wybierając z menu View→Resource View.
Struktura TBBUTTON
Struktura TBBUTTON służy do opisywania styli i właściwości poszczególnych przycisków okna kontrolki toolbar. Z tego względu warto się przyjrzeć co niektórym polom tej struktury:
- iBitmap - indeks wycinka bitmapy, który zostanie przypisany do danego przycisku. Pierwszym elementem indeksowania jest zero;
- idCommand - identyfikator przycisku, który zostanie wysłany w komunikacie WM_COMMAND;
- fsState - określa stan przycisku, ten element może mieć jedną z następujących kombinacji:
- TBSTATE_CHECKED - przycisk ma styl TBSTYLE_CHECK i wyświetla się jako już kliknięty;
- TBSTATE_ELLIPSES - przycina wyświetlany tekst i wyświetla trzy kropek;
- TBSTATE_ENABLED - odblokowany przycisk (przycisk bez tego stylu jest wyszarzony i nieaktywny;
- TBSTATE_HIDDEN - przycisk jest niewidoczny i nie może otrzymywać komunikatów od użytkownika;
- TBSTATE_INDETERMINATE - przycisk jest wyszarzony;
- TBSTATE_PRESSED - przycisk jest wciśnięty;
- TBSTATE_WRAP - oznacza, że następne przyciski będą wstawiane w nowej linii, ta flaga musi być użyta wraz z flagą TBSTATE_ENABLED;
- fsStyle - określa styl przycisku, oto zbiór dostępnych flag:
- BTNS_AUTOSIZE - toolbar nie będzie wykorzystywał standardowej szerokości dla przycisku, zamiast tego długość ta będzie obliczana na podstawie szerokości obrazka oraz tekstu przypisanego do przycisku;
- BTNS_BUTTON tworzy standardowy przycisk. Odpowiednikiem tego stylu jest TBSTYLE_BUTTON;
- BTNS_CHECK - tworzy przycisk podwójnego stanu: wciśniętego lub nie wciśniętego za każdym razem, gdy użytkownik kliknie kontrolkę. Przycisk ma inny kolor tła gdy jest w stanie wciśnięcia. Odpowiednikiem tego stylu jest TBSTYLE_CHECK;
- BTNS_CHECKGROUP - tworzy przycisk, który pozostaje wciśnięty dopóki następny przycisk z tej samej grupy nie zostanie naciśnięty;
- BTNS_DROPDOWN - tworzy rozwijany przycisk, który może wyświetlać listę, gdy przycisk jest kliknięty. Zamiast komunikatu WM_COMMAND używanego dla normalnych przycisków, przycisk rozwijany wysyła notyfikację TBN_DROPDOWN. Aplikacja może wtedy otrzymać listę opcji. Jeżeli toolbar ma styl TBNSTYLE_EX_DRAWDDARROWS, przycisk rozwijany będzie miał ikonkę wyświetlaną z lewej jego strony. Gdy strzałka zostanie kliknięta to wysyłany jest komunikat TBN_DROPDOWN, natomiast, gdy przycisk zostanie kliknięty, to wysyłany jest komunikat WM_COMMAND;
- BTNS_GROUP - gdy jest użyty wraz z stylem BTNS_CHECK, tworzy przycisk, który pozostaje wciśnięty dopóki inny przycisk w grupie nie zostanie wciśnięty;
- BTNS_NOPREFIX - tekst przycisku nie będzie wyświetlał prefiksów związanych z akceleratorami;
- BTNS_SEP - wstawia separator pomiędzy różnymi grupami przycisków;
- BTNS_SHOWTEXT - określa, że tekst przycisku powinien zostać wyświetlony. Każdy przycisk może mieć przypisany tekst, ale tylko te, które mają ustawiony ten styl będą go wyświetlały. Gdy styl ten nie jest ustawiony a przyciski mają przypisany tekst, wtedy tekst będzie się pojawiał dopiero po najechaniu kursorem myszki na dany przycisk;
- BTNS_WHOLEDROPDOWN - przycisk będzie miał strzałkę rozwijania, lecz nie jako oddzielną część;
- dwData - dodatkowe dane zdefiniowane w programie;
- iString - indeks tekstu, który jest przypisany do przycisku;
Funkcja CreateToolbarEx
Oto nagłówek funkcji, która tworzy uchwyt okna kontrolki toolbar:
- HWND CreateToolbarEx(
- HWND hwnd, // uchwyt rodzica
- DWORD ws, // styl okna
- UINT wID, // identyfikator kontrolki
- int nBitmaps, // id bitmapy zawartej w pliku zasobów .rc
- HINSTANCE hBMInst, // uchwyt instancji programu
- UINT_PTR wBMID, // liczba przycisków
- LPCTBBUTTON lpButtons, // wskaźnik do tablicy struktur opisujących przyciski
- int iNumButtons, // liczba elementów tablicy struktur opisujących przyciski
- int dxButton, // szerokość przycisku
- int dyButton, // wysokość przycisku
- int dxBitmap, // szerokość bitmapy
- int dyBitmap, // wysokość bitmapy
- UINT uStructSize // rozmiar struktury TBBUTTON
- );
Zasadniczo wszystkie parametry funkcji CreateToolbarEx zostały omówione w komentarzach nagłówka funkcji, jednak warto rozpisać się nieco na temat parametru ws, który określa style okna. Style te mogą przybierać następujące wartości:
- TBSTYLE_ALTDRAG - umożliwia użytkownikowi zmianę położenia przycisków toolbar-a poprzez kliknięcie i przeciągnięcie przycisku z przytrzymanym klawiszem alt. Jeżeli ten styl nie został zastosowany, użytkownik musi wcisnąć i przytrzymać klawisz shift gdy przycisk jest przeciągany. Aby ten styl zadziałał i aby przeciąganie było możliwe trzeba użyć stylu CCS_ADJUSTABLE;
- TBSTYLE_CUSTOMERASE - generuje notyfikację NM_CUSTOMDRAW gdy toolbar przetwarza komunikat WM_ERASEBKGND;
- TBSTYLE_FLAT - przyciski toolbar-a są rysowane bez trójwymiarowej ramki;
- TBSTYLE_LIST - przyciski toolbar-a są rysowane bez trójwymiarowej ramki, natomiast tekst dołączony do przycisków jest rysowany po prawej stronie bitmapy przycisku;
- TBSTYLE_REGISTERDROP - generuje notyfikację TBN_GETOBJECT przy żądaniu upuszczenia obiektu gdy kursor przechodzi ponad oknem toolbar;
- TBSTYLE_TOOLTIPS - tworzy kontrolki toolbar-u wyświetlając informację o przeznaczeniu danego przycisku;
- TBSTYLE_TRANSPARENT - tworzy toolbar z przezroczystym tłem. Tło przycisków pozostaje niezmienione (nie jest przezroczyste);
- TBSTYLE_WRAPABLE - tworzy toolbar, który może mieć wiele linii. Kontrolka ta utworzona z tym stylem zwija przyciski i wyświetla je w nowej linii, gdy te nie mieszczą się w oknie. Styl ten nie może być użyty z stylem CCS_VERT;
Istnieje jeszcze oddzielna grupa stylów, które mogą również być użyte w parametrze ws funkcji CreateToolbarEx:
- CCS_ADJUSTABLE - odblokowuje ustawienie dla kontrolki toolbar możliwości przeciągania przycisków do nowej pozycji lub ich usuwanie z listy toolbar-a;
- CCS_BOTTOM - ustawia kontrolkę wyrównując ją do dolnej krawędzi okna rodzica z wyrównaniem do lewej jego strony oraz ustawia szerokość na równi z tymże oknem. Kontrolka typu statusbar ma ten styl ustawiony jako domyślny;
- CCS_LEFT - ustawia kontrolkę tak, że jest ona wyświetlana poziomo z wyrównaniem do lewej krawędzi okna rodzica;
- CCS_NODIVIDER - wyłącza rysowanie krawędzi kontrolki, która jest rysowana na jej górnej krawędzi;
- CCS_NOMOVEX - kontrolka może przemieszczać się i zmieniać rozmiar w poziomie, lecz nie w pionie w odpowiedzi na komunikat WM_SIZE. Jeżeli został użyty styl CCS_NORESIZE ten styl nie ma zastosowania;
- CCS_NOMOVEY - kontrolka może przemieszczać się i zmieniać rozmiar w pionie, lecz nie w poziomie w odpowiedzi na komunikat WM_SIZE. Jeżeli został użyty styl CCS_NORESIZE ten styl nie ma zastosowania;
- CCS_NOPARENTALIGN - zapobiega przed automatycznym przemieszczaniem kontrolki do górnej lub dolnej krawędzi okna rodzica. Zamiast tego kontrolka utrzymuje położenie dostosowując jedynie swój rozmiar do rozmiaru okna rodzica. Jeżeli styl CCS_TOP lub CCS_BOTTOM jest również użyty, wtedy szerokość jest ustawiana na domyślną wartość, ale pozycja i szerokość się nie zmieniają;
- CCS_NORESIZE - zapobiega przed zmianą pozycji oraz szerokości i wysokości okna kontrolki;
- CCS_RIGHT - wyrównuje poziomo do prawej krawędzi okna;
- CCS_TOP - wyrównuje do górnej krawędzi okna, kontrolka typu toolbar ma ten styl ustawiony domyślnie;
- CCS_VERT - tworzy kontrolkę wyświetlaną poziomo;
Kod programu
Przed rozpoczęciem wpisywania kodu należy kliknąć w menu Projekt→Rysowanie Properties lub wcisnąć kombinację klawiszy alt+F7 aby pojawiło się okno Rysowanie Property Page. W oknie tym w liście rozwijanej po lewej stronie należy kliknąć pozycję Configuration Properties→Linker→Input i w kontrolce po prawej stronie w polu Additional Dependencies wpisać nazwę pliku comctl32.lib. Skoro już wiadomo co i jak, teraz pozostało już napisanie jedynie kodu programu:
- #include <windows.h>
- #include <commctrl.h>
- #include "resource.h"
- // ############## ID TOOLBAR-a ####################
- #define TB_ID 100
- // ############## ID PRZYCISKÓW TOOLBARD-a ##############
- #define ID_LINE 100
- #define ID_CIRCLE 101
- #define ID_RECTANGLE 102
- #define ID_SELECT 103
- // ###################### UCHWYT TOOLBAR-a #######################
- HWND toolbar;
- // ################## PROCEDURA OKNA GŁÓWNEGO #######################
- LRESULT CALLBACK WndParentProc(HWND hParent, UINT msg, WPARAM wParam, LPARAM lParam){
- switch(msg){
- case WM_SIZE:
- {
- SendMessage(toolbar, TB_AUTOSIZE, NULL, NULL); // okunikat wysyłany w celu automatycznego ustawienia wymiarów okna toolbar
- }
- break;
- case WM_COMMAND:
- {
- if((HWND)lParam == toolbar){
- switch(LOWORD(wParam)){
- case ID_LINE: // komunikat przychodzący od przycisku toolbar-a o identyfikatorze ID_LINE
- {
- MessageBox(hParent, L"Kliknięto przycisk rysowania linii",L"Info",MB_OK);
- }
- break;
- case ID_CIRCLE: // to samo co poprzednio, tylko dla ID_CIRCLE
- {
- MessageBox(hParent, L"Kliknięto przycisk rysowania okręgu",L"Info",MB_OK);
- }
- break;
- case ID_RECTANGLE: // to samo co poprzednio, tylko dla ID_RECTANGLE
- {
- MessageBox(hParent, L"Kliknięto przycisk rysowania prostokąta",L"Info",MB_OK);
- }
- break;
- case ID_SELECT: // to samo co poprzednio, tylko dla ID_SELECT
- {
- MessageBox(hParent, L"Kliknięto przycisk zaznaczania",L"Info",MB_OK);
- }
- break;
- }
- }
- }
- break;
- case WM_DESTROY:
- {
- PostQuitMessage(0);
- }
- break;
- }
- return DefWindowProc(hParent,msg, wParam, lParam);
- }
- int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int){
- // ####################### Operacje związane z rejestracją okna głównego ########################
- wchar_t parentWndClass[] = L"Okno główne programu Rysowanie";
- WNDCLASS wnd;
- wnd.cbClsExtra = NULL;
- wnd.cbWndExtra = NULL;
- wnd.hbrBackground = NULL;
- wnd.hCursor = LoadCursor(NULL, IDC_ARROW);
- wnd.hIcon = LoadIcon(NULL, IDC_ICON);
- wnd.hInstance = hInst;
- wnd.lpfnWndProc = WndParentProc;
- wnd.lpszClassName = parentWndClass;
- wnd.lpszMenuName = NULL;
- wnd.style = CS_VREDRAW|CS_HREDRAW;
- if(!RegisterClass(&wnd)){
- MessageBox(NULL, L"Nie zarejestrowano klasy okna", L"Błąd", MB_OK);
- return 0;
- }
- HWND parent_window = CreateWindow(parentWndClass, L"Rysowanie", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL);
- // ################# Inicjalizowanie tablicy struktur niezbędnej do utworzenia toolbar-a #########################
- TBBUTTON bt[4]; // tablica struktur przycisków toolbar-a
- int i = 0; // indeks
- bt[i].dwData = 0; // brak dodatkowych danych
- bt[i].fsState = TBSTATE_ENABLED; // stan przycisku (w tym przypadku odblokowany)
- bt[i].fsStyle = TBSTYLE_CHECKGROUP; // styl przycisku (w tym przypadku grupowanie z innymi przyciskami)
- bt[i].iBitmap = i; // indeks wycinka bitmay
- bt[i].idCommand = ID_LINE; // identyfikator przycisku dla rysowania linii
- bt[i].iString = i; // indeks tekstu wyświetlanego pod przyciskiem
- i++;
- bt[i].dwData = 0;
- bt[i].fsState = TBSTATE_ENABLED;
- bt[i].fsStyle = TBSTYLE_CHECKGROUP;
- bt[i].iBitmap = i;
- bt[i].idCommand = ID_CIRCLE; // idnetyfikator przycisku dla rysowania okręgu
- bt[i].iString = i;
- i++;
- bt[i].dwData = 0;
- bt[i].fsState = TBSTATE_ENABLED;
- bt[i].fsStyle = TBSTYLE_CHECKGROUP;
- bt[i].iBitmap = i;
- bt[i].idCommand = ID_RECTANGLE; // identyfikator przycisku dla rysowania prostokąta
- bt[i].iString = i;
- i++;
- bt[i].dwData = 0;
- bt[i].fsState = TBSTATE_ENABLED;
- bt[i].fsStyle = TBSTYLE_CHECKGROUP;
- bt[i].iBitmap = i;
- bt[i].idCommand = ID_SELECT; // identyfikator przycisku dla zaznaczania obiektów
- bt[i].iString = i;
- toolbar = CreateToolbarEx( // tworzenie toolbar-a
- parent_window, // okno rodzica
- WS_CHILD|WS_VISIBLE|TBSTYLE_FLAT|TBSTYLE_WRAPABLE, // style: okno potomne; widoczny; płaskie przyciski; przyciski zwijane, gdy nie mogą się zmieścić w oknie programu
- TB_ID, // identyfikator toolbar-a
- 4, // liczba fragmentów wycinanych z bitmapy
- hInst, // uchwyt instancji programu
- IDB_TB_BITMAP, // identyfikator bitmapy zawartej w zasobach programu
- bt, // tablica struktur opisujących przyciski
- 4, // rozmiar tablicy struktur opisujących przyciski
- 48, // szerokość przycisku
- 48, // wysokość przycisku
- 42, // szerokość bitmapy
- 42, // wysokość bitmapu
- sizeof(TBBUTTON) // rozmiar struktury TBBUTTON
- );
- SendMessage(toolbar, TB_ADDSTRING, 0, (LPARAM)L"Odcinek Okrąg Prostokąt Zaznaczanie "); // ustawianie tekstu pod obrazkami przycisków toolbar-u
- SendMessage(toolbar, TB_AUTOSIZE, NULL, NULL); // automatyczne dostosowanie rozmiaru okna do okna rodzica
- RECT r;
- POINT pt;
- SendMessage(toolbar,TB_GETRECT,ID_LINE,(LPARAM)&r); // pobieranie prostokąta przycisku o identyfikatorze ID_LINE
- // tutaj pozyskuję współrzędne środka przycisku
- pt.x = (r.right + r.left) / 2;
- pt.y = (r.bottom + r.top) / 2;
- // A tutaj wysyłam komunikaty WM_LBUTONDOWN i WM_LBUTTONUP w celu zaznaczenia przycisku o identyfikatorze ID_LINE
- SendMessage(toolbar,WM_LBUTTONDOWN,MK_LBUTTON,MAKELONG(pt.x,pt.y));
- SendMessage(toolbar,WM_LBUTTONUP,MK_LBUTTON,MAKELONG(pt.x,pt.y));
- ShowWindow(parent_window, SW_NORMAL);
- UpdateWindow(parent_window);
- MSG msg;
- while(GetMessage(&msg, 0,0,0)){
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return 0;
- }
Na koniec mały podgląd programu zamieszczam poniżej.


Tytuł:
Architektura oprogramowania bez tajemnic. Wykorzystaj język C++ do tworzenia wydajnych aplikacji i systemów
Autor:
Adrian Ostrowski, Piotr Gaczkowski

Tytuł:
Opus magnum C++ 11. Programowanie w języku C++. Wydanie II poprawione (komplet)
Autor:
Jerzy Grębosz

Tytuł:
Programowanie wieloplatformowe z C++ i wxWidgets 3
Autor:
Bartosz W. Warzocha

Tytuł:
Język C++ i przetwarzanie współbieżne w akcji. Wydanie II
Autor:
Anthony Williams

Tytuł:
C++ dla bystrzaków. Wydanie VII
Autor:
Stephen R. Davis

Tytuł:
Tablice informatyczne. Podstawy C++
Autor:
Radosław Sokół

Tytuł:
Opus magnum C++11. Programowanie w języku C++ (komplet)
Autor:
Jerzy Grębosz

Tytuł:
OpenCV 3. Komputerowe rozpoznawanie obrazu w C++ przy użyciu biblioteki OpenCV
Autor:
Adrian Kaehler, Gary Bradski

Tytuł:
C++ w 24 godziny. Wydanie VI
Autor:
Rogers Cadenhead, Jesse Liberty

Tytuł:
C++ Optymalizacja kodu. Sprawdzone techniki zwiększania wydajności
Autor:
Guntheroth Kurt