Buchempfehlung
Windows System Programming
Windows System Programming
Das Kompendium liefert viele interessante Informationen zur Windows-Programmierung auf Englisch. [Mehr Infos...]
FreeBASIC-Chat
Es sind Benutzer im FreeBASIC-Chat online.
(Stand:  )
FreeBASIC bei Twitter
Twitter FreeBASIC-Nachrichten jetzt auch über Twitter erhalten. Follow us!

Tutorial

Toolbar mit eigenen Icons

von MitgliedstephanbrunkerSeite 1 von 1

Nachdem es für die Toolbar-Programmierung (Toolbar-Demo) ein kurzes Code-Beispiel gibt, das aber nicht sehr ausführlich ist und auch nur die von Windows standardmäßig bereitgestellten Icons verwendet, besteht also etwas Nachholbedarf. Denn wenn man eine halbwegs modern aussehende Oberfläche programmieren will, dann gehören dazu schöne große Icons auf transparentem Hintergrund (weil der hier weiß und nicht Dialog-grau ist). Also etwa so:

ToolbarTut1

1. Schritt: Bitmaps anlegen

Wie stellt man das an? Zuerst benötigen wir für die Toolbar eine 32bit *.bmp Bitmap, in der alle Icons nebeneinander stehen. Und von diesen Bitmaps benötigen wir mindestens zwei, nämlich eine aktive und eine ausgegraute Version. Prinzipiell gibt es noch eine dritte, nämlich die gedrückte Version, aber die fabriziert Windows ab den Common Controls 6.0 (also XP) und der Toolbar auf TBSTYLE_FLAT selbst. Bildbearbeitung muss ich glaube ich hier nicht weiter erläutern, die Bitmaps werden also z.B. 32 Pixel hoch und 32 x Anzahl der Icons breit.

Toolbar Bitmaps

Zwei kleine Hinweise noch: Die wenigsten Programme können Windows-bmp als 24bit RGB mit 8bit Alpha-Kanal für die Transparenz. Da aber jedes Bildbearbeitungsprogramm PNG erzeugen kann, die man mit Transparenz speichern kann ist das also das Format der Wahl. Bei den Konvertern treiben sich zwar extra viele zweifelhafte Programme herum (zehn Download-Buttons auf der Seite und der kleinste ist das eigentliche Programm ...), aber dieses kleine Prog funktioniert einwandfrei: Externer Link!PNGtoBMP32 - einfach die png-Datei auf das Programmfenster ziehen und es erzeugt im gleichen Verzeichnis die gewünschte BMP. Und ein zweiter Tipp wäre für die ausgegrauten Icons: Zu Graustufen konvertieren - Schwarzwerte zu grau komprimieren - Richtungschärfen - nochmals komprimieren und wieder zu RGB umwandeln erzeugt die gewünschten grauen Icons mit verstärkten Konturen.

2. Schritt: Bitmaps laden

Um die Icons aufzunehmen, benötigen wir zwei ImageLists, für normal und disabled. Die dazugehörigen shared-Dimensionierungen schreibe ich jeweils an den Anfang, die gehören natürlich in die *.bi - Datei:

    Dim Shared As HIMAGELIST hILTool1, hILTool2

    hILTool1 = ImageList_Create(32,32,ILC_MASK Or ILC_COLOR32,11,1)
    hILTool2 = ImageList_Create(32,32,ILC_MASK Or ILC_COLOR32,11,1)

Die ersten zwei Parameter sind Höhe und Breite, die Flag sagt 32-bit mit Alphakanal und im Beispiel die "11" sind die Anzahl der Plätze in der Imagelist. Die Bitmaps fügen wir außerdem als Resource in unser Projekt ein, hier unter IDC_TOOL1 und IDC_TOOL2.

    'load bitmaps
    Dim As HBITMAP hBmpNorm, hBmpDis
    hBmpNorm = LoadImage(hInstance,Cast(Any Ptr,IDC_TOOL1),IMAGE_BITMAP,416,32,LR_DEFAULTCOLOR)
    hBmpDis = LoadImage(hInstance,Cast(Any Ptr,IDC_TOOL2),IMAGE_BITMAP,416,32,LR_DEFAULTCOLOR)
    'Add bitmaps to imagelists -> automatic split
    ImageList_Add(hILTool1,hBmpNorm,0)
    ImageList_Add(hILTool2,hBmpDis,0)
    DeleteObject(hbmpNorm)
    DeleteObject(hbmpDis)

Was passiert da? Wir laden zuerst die Bitmap aus der Resource mit LoadImage (wobei 416 hier wieder die Breite ist (11x32) ), den HBITMAP-Handle laden wir dann in die Imagelist mit ImageList_Add, wobei wenigstens das Auseinanderbrechen in einzeine Icons dann automatisch geht. Das geladene Image-Objekt können wir dann wieder löschen.

3. Schritt: Toolbar konfigurieren

Wenn wir dann die Toolbar in unserem Dialog-Template angelegt haben, z.B. als IDC_TBR1 im Editor von FBEdit, dann initialisieren wir diese. Im Template geben wir die Windows-Styles für die Toolbar an, in dem Beispiel oben ist das TBSTYLE_TRANSPARENT, TBSTYLE_FLAT, CCS_NODIVIDER und CCS_TOP
Wir müssen dann der Toolbar sagen, wie sie denn aussehen soll. Dazu holen wir uns den Handle der Toolbar und schicken ihr eine Reihe von Messages:

    Dim Shared As HWND hTBR1

    'get Handle
    hTBR1 = GetDlgItem(hTabWin(0),IDC_TBR1)

    'toolbar properties
    ReDim tbb(0 To 8) As TBBUTTON
    SendMessage(hTBR1, CCM_SETVERSION, 5, 0)
    SendMessage(hTBR1, TB_SETIMAGELIST,NULL,Cast(lparam,hILTool1))              'imagelist normal
    SendMessage(hTBR1, TB_SETDISABLEDIMAGELIST,NULL,Cast(lparam,hILTool2))  'imagelist disabled
    SendMessage(hTBR1, TB_SETMAXTEXTROWS,2,NULL)                                        'two lines of text
    SendMessage(hTBR1, TB_SETBUTTONWIDTH,NULL,MAKELONG(80,80))                  'width min 80 max 80
    SendMessage(hTBR1, TB_BUTTONSTRUCTSIZE, Len((tbb)), NULL )

Das Array tbb enthält einen Eintrag für jeden unserer Toolbar-Buttons - und Platzhalter. Hier sind es nur neun, denn wir können aus einem Paar Imagelists auch mehrere Toolbars versorgen. CCM_SETVERSION setzt den XP-Stil. Dann folgen die Imagelisten. Es gibt die Toolbar mit und ohne Text, das liest man dann ausführlich in der MSDN nach. Hier haben wir zwei Zeilen Text unter dem Button und eine feste Breite von 80 Pixeln. BUTTONSTRUCTSIZE ist dann die Anzahl der Buttons.

4. Schritt: Buttons definieren

Dieses Array füllen wir jetzt mit Leben, da das in dem Beispiel alles normale Buttons sind, mit einer For..Next Schleife. Wenn es komplizierter wird, muss man halt jeden Button einzeln definieren, hier geht das en bloc:

    Dim i As Byte
    For i = 0 To 8
        tbb(i).fsStyle = TBSTYLE_BUTTON 'Or BTNS_AUTOSIZE
        tbb(i).iBitmap = MAKELONG(i,0)
        tbb(i).fsState = TBSTATE_ENABLED
        tbb(i).idCommand = 11000 + i 'TB_OPEN to TB_CLOSE
        tbb(i).iString = CInt(StrPtr(TBText(i)))
    Next i

    SendMessage( hTBR1, TB_ADDBUTTONS, 9, cint( @tbb(0) ) )
    SendMessage( hTBR1, TB_AUTOSIZE, NULL, NULL )

Dabei ist iBitmap die dazugehörige Nummer der ImageList, fsState setzen wir erstmal auf Enabled. IDCommand ist der Parameter, der bei als WM_COMMAND-Message ausgegeben wird, wenn der Button gedrückt wird. Um hier nicht mit abstrakten und daher unübersichtlichen Zahlen zu jonglieren, kann man sich das in der *.bi mit Text hinterlegen:

    #Define TB_OPEN 11000
    #Define TB_NEWSYMM 11001
    #Define TB_NEWASSYMM 11002
    #Define TB_INFO 11003
    ...

iString ist dann ein Pointer zu dem dazugehörigen Text, den man sich auch als Array vorher definieren sollte:

    Dim Shared TBText(0 To 15) As String

    TBText(0) = "Archiv öffnen"
    TBText(1) = "neu symmetrisch"
    TBText(2) = "neu assymmetrisch"
    TBText(3) = "Info"

Einmal kurz abschweifen: Eine sehr einfache Version der Internationalisierung arbeitet einfach damit, alle verwendeten Texte als solche String-Arrays abzuspeichern, für jede Sprache muss man dann nur mit der passenden Datei kompilieren, in der alle Strings definiert werden.

Die so gefüllte TBBUTTON-Struktur übergeben wir dann an die Toolbar und lassen danach nochmal AUTOSIZE darüberlaufen. Als letzten Schritt deaktivieren wir die Buttons, die wir beim Start nicht aktiv wollen:

    SendMessage( hTBR1, TB_SETSTATE, TB_INFO, FALSE)
    SendMessage( hTBR1, TB_SETSTATE, TB_SAVEFILE, FALSE)

5. Schritt: Toolbar-Klicks verarbeiten

Das ist jetzt einfach: Wie schon vorher erwähnt, erzeugt ein Klick auf die Toolbar eine WM_COMMAND / BN_CLICKED - Message, auf die wir entsprechend reagieren, sollte bekannt sein. In obigem Beispiel ist die Toolbar bei ID's von 11000 aufwärts, damit sie nicht mit den "normalen" Buttons kollidiert, die vierstellige ID's haben. Kann man machen wie man will, da das Menü oft ab 10000 läuft, habe ich eben 11000 genommen.

6. Schritt: Feinheiten und Möglichkeiten

Zusätzlich zu dem Toolbar-Text kann man auch noch einen Tooltip definieren. Macht man nichts, wird der beim Button definierte Text genommen. Wenn man eine Toolbar ohne Text hat, macht das auch Sinn. Ansonsten gibt es dafür die TBN_GETINFOTIP - Message. Die fehlt im Moment leider noch wie so manches andere in den Windows-Headern, deshalb müssen wir das selbst definieren:

    'Toolbar constants
    #Define TBN_GETINFOTIP (TBN_FIRST-18)
    Type NMTBGETINFOTIP
        hdr As NMHDR
        pszText As LPTSTR
        cchTextMax As Integer
        iItem As Integer
        lparam As LPARAM
    End Type
    Type LPNMTBGETINFOTIP As  NMTBGETINFOTIP Ptr

Auf die WM_NOTIFY / TBN_GETINFOTIP - Message reagieren wir dann etwa so:

    Case TBN_GETINFOTIP
        'set Tooltips for Toolbar
        Dim pnmgit As NMTBGETINFOTIP Ptr = Cast(NMTBGETINFOTIP Ptr, lparam)
        If TBTooltip(pnmgit->iItem) = "" Then
            Return FALSE
        Else
            pnmgit->pszText = StrPtr(TBTooltip(pnmgit->iItem))
            pnmgit->cchTextMax = Len((TBTooltip(pnmgit->iItem)))
        EndIf

Wobei wir hier wieder ein Array aus Strings TBTooltip() als Speicher für die Texte nehmen und Pointer und Länge in die der gewünschte Struktur zurückgeben, bzw. FALSE wenn wir keinen Tooltip wollen oder der Eintrag nur ein Platzhalter ist.

Besagte Platzhalter können wir erzeugen, wenn wir in der TBBUTTONS-Struktur das fsStyle-Member auf BTNS_SEP setzen, das iBitmap-Member ist dann die Breite des Platzhalters in Pixeln. Einen solchen Platzhalter können wir zum Beispiel verwenden, um andere Kontrollelemente in die Toolbar zu integrieren. Das bekannteste Beispiel dürfte das Listenfeld für die Schriftarten in Word sein, aber Radiobuttons gehen auch:

ToolbarTut3

Damit diese Kontrollelemente richtig dargestellt werden, müssen wir da noch eine Verwandschaftsbeziehung angeben:

    'set toolbar as parent for integrated controls
    SetParent(hRBN3, hTBR2)

Für das Listenfeld oder Buttons, die in einer Check-Version arbeiten, gibt es auch vordefinierte fsStyles direkt in der Toolbar, das ist in der MSDN ganz gut beschrieben. Die Lektüre lohnt sich, denn wenn man die Grundlagen erstmal hat, dann versteht sich der Rest deutlich einfacher:

Externer Link!MSDN-Toolbar

 

Zusätzliche Informationen und Funktionen
  Bearbeiten Bearbeiten  

  Versionen Versionen