Autor podstrony: Krzysztof Zajączkowski

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

Bitmapa ta powinna wyglądać mniej więcej tak jak na poniższym rysunku, i zostanie ona użyta przy tworzeniu paska narzędziowego.

Bitmapa pliku zasobów dla toolbar-a
Rys. 1
Bitmapa pliku zasobów dla toolbar-a

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:

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:

Istnieje jeszcze oddzielna grupa stylów, które mogą również być użyte w parametrze ws funkcji CreateToolbarEx:

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"OdcinekOkrągProstokątZaznaczanie"); // 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.

Podgląd programu Rysowanie
Rys. 2
Podgląd programu Rysowanie