Windows Programmierung: Toolbar
Willemers Informatik-Ecke

Vorarbeiten

Die Toolbar gehört zu den Common Controls. Es muss also die Headerdatei commctrl.h eingebunden werden.

#include <commctrl.h>

Kommt es zu nicht aufgelösten Externals, sollte man prüfen, ob die Library für die Common Controls (comctl32.lib) eingebunden wird.

Erzeugen: die Funktion CreateToolbarEx

HWND CreateToolbarEx(
    HWND hwnd,	
    DWORD styles,	
    UINT wID, 	
    int nBitmaps, 	
    HINSTANCE hBMInst, 	
    UINT wBMID, 	
    LPCTBBUTTON lpButtons, 	
    int iNumButtons, 	
    int dxButton, 	
    int dyButton, 	
    int dxBitmap, 	
    int dyBitmap, 	
    UINT uStructSize	
);

Parameters

hwnd
Handle des Elternfenster.
styles
Window Styles des Toolbar. Der Parameter muss mindestens WS_CHILD enthalten, WS_VISIBLE macht die Toolbar gleich nach Start sichtbar.
wID
Kontroll-ID des Toolbar
nBitmaps
Anzahl der Images, die in der Bitmap enthalten sind, die durch hBMInst und wBMID bezeichnet wird.
hBMInst
Normalerweise die Modul-Instanz des eigenen Programms.
wBMID
Ressource ID der Bitmap
lpButtons
Adresse des Arrays der TBBUTTON-Struktur, das die Information über die Buttons des Toolbars enthält
iNumButtons
Anzahl der Buttons inklusive Separatoren in der Toolbar
dxButton
Breite der Buttons in Pixel (meist 16)
dyButton
Höhe der Buttons in Pixel (meist 16)
dxBitmap
Breite der Images in Pixel (meist 16)
dyBitmap
Höhe der Images in Pixel (meist 16)
uStructSize
Grösse einer TBBUTTON-Struktur
Der Rückgabewert ist bei Erfolg das Handle des Toolbars, ansonsten 0. GetLastError liefert erweiterte Fehlermeldungen.

Wird als Instanz als Konstante HINST_COMMCTRL verwendet, kann man auf die vordefinierten Buttons des Systems zugreifen wie STD_FILEOPEN oder VIEW_DETAILS. IDB_STD_SMALL_COLOR als Bitmap-ID und

Die Struktur TBBUTTON

// Definition
typedef struct _TBBUTTON {
    int iBitmap;
    int idCommand;
    BYTE fsState; 
    BYTE fsStyle;
    DWORD dwData;
    int iString;
} TBBUTTON;
iBitmap
Index im Image, nullbasierend
idCommand
Die ID, die der Button liefern soll, wenn er ein WM_COMMAND auslöst. Im Allgemeinen verwendet man hier die gleiche ID wie der entsprechende Menüpunkt.
fsState
Der Status des Buttons. Meist steht hier TBSTATE_ENABLED.
fsStyle
Der Stil des Button. Meist steht hier nur TBSTYLE_BUTTON.
dwData
Applikationswert
iString
Nullbasierender Index des Button-Strings (meist 0)
Ein Array der Struktur wird verwendet, um mit CreateToolbarEx ein Toolbar zu erzeugen. Meist wird dies als Konstante festgelegt, wie in folgendem Beispiel:

// Die Konstante...
TBBUTTON tbButtons [] = {
	{0, IDM_NEW, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
	{1, IDM_OPEN, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
	{2, IDM_SAVE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
	{0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0L, 0},
	{3, IDM_CUT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
	{4, IDM_PASTE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
}; 

Ein einfaches Beispiel

#define BITMAPCOUNT	4
// Die Konstante...
TBBUTTON Buttons [] = {
	{0, IDM_NEW, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
	{1, IDM_OPEN, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
	{2, IDM_SAVEAS, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
	{0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0L, 0},
	{3, IDM_EXIT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0},
}; 


HWND CreateToolBar(HWND hWnd, UINT ResID)
{
	return CreateToolbarEx(hWnd, WS_CHILD | WS_VISIBLE,
		ResID,	// des Toolbars
		BITMAPCOUNT, hInst, IDR_TOOLBAR, Buttons, 	
		sizeof(Buttons)/sizeof(TBBUTTON),
		16,16,16,16,
		sizeof(TBBUTTON)
		);
}

Auf die WM_CREATE-Nachricht des Hauptfensters wird CreateToolBar aufgerufen. Eine Toolbar-Ressource mit Namen IDR_TOOLBAR wird mit dem Ressource-Editor angelegt. Die Menüeinträge IDM_NEW, IDM_OPEN, IDM_SAVEAS und IDM_EXIT sind damit per Toolbar erreichbar.

Damit die Toolbar nicht von anderen Elementen des Fensters übermalt wird, ist noch die folgende WM_SIZE-Bearbeitung notwendig.

WM_SIZE

Das Einbinden des Toolbars geht nicht soweit, dass Windows die Grösse des Client-Bereichs selbststänig verkleinert. Dies muss von Hand in der Fensterfunktion erledigt werden. Im folgenden Beispiel soll ein Edit-Element den gesamten Bereich des Hauptfensters einnehmen, aber natürlich nicht den Bereich des Toolbars.

	case WM_SIZE:
            RECT rcl;
            SendMessage(hToolbar, TB_AUTOSIZE, 0L, 0L);
            GetWindowRect(hToolbar, &rcl);
            MoveWindow(hEdit, 0, rcl.bottom - rcl.top, LOWORD(lParam), HIWORD(lParam), TRUE );
	    break;

Mit TB_AUTOSIZE wird die Toolbar aufgefordert, ihre optimale Grösse festzulegen. Anschliessend wird eben diese erfragt und vom Clientbereich des Fensters abgezogen.

Tooltips

Hat die Toolbar den Style TBSTYLE_TOOLTIPS, wird es WM_NOTIFY-Nachrichten vom Typ TTN_NEEDTEXT an das Elternfenster senden, wenn der Mauscursor über einem Button länger stehen bleibt. Die Anwendung erfährt, welche Command-ID der Button hat und kann daraus ermitteln, welcher Text im Tooltip erscheinen sollte. Hier ist dies durch Laden eines Stringtable der Ressource realisiert.

	case WM_NOTIFY:
		switch (((LPNMHDR)lParam)->code) {
		LPTOOLTIPTEXT lpToolTipText;
		static char szBuf[80];

		case TTN_NEEDTEXT: // tooltip meldet sich und will einen Text
			lpToolTipText = (LPTOOLTIPTEXT)lParam;
			LoadString (hInst, lpToolTipText->hdr.idFrom,
				szBuf, sizeof (szBuf));
			lpToolTipText->lpszText = szBuf;
			break;
		}
		break;

Nun muss lediglich für jede Command-ID unter dieser Nummer auch ein Stringtable in der Ressource angelegt werden.

Einsetzen anderer Kontrollelemente

Man kann andere Elemente, wie etwa Comboboxen oder Editfelder in die Toolbar einsetzen. Dazu wird die HWND des Toolbar als Eltern-HWND mitgegeben. Um Freiraum für solche Elemente zu schaffen, wird im TBBUTTON-Array eine Reihe von TBSTYLE_SEP-Elementen hintereinander gesetzt.

Man kann ausprobieren, wieviele freie Plätze man braucht. Man kann aber auch eine Nachricht TB_GETITEMRECT an einen Seperator senden und aus dem zurückgegebenen RECT durch (right-left) die Breite ermitteln.