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

Erste Schritte in der WinAPI mit Freebasic und FBEdit

von MitgliedstephanbrunkerSeite 12 von 13

Menü

Um dem Fenster ein Menü hinzuzufügen, hat FBEdit einen halbwegs guten Assistenten. Man erzeugt das Menü mit "Ressourcen->Menü hinzufügen" und wählt das Menü IDR_MENU1 im Editor aus, woraufhin sich der passende Editor öffnet:

Das Menü hat jetzt nur zwei Hauptpunkte: Datei und Hilfe, die stehen linksbündig. Die Untereinträge sind dann mit der "->" Taste eingerückt. Während die Hauptauswahl keine ID und keinen Namen hat, bekommen die Menüeinträge einen Namen und eine ID wie andere Windows Controls auch, z.B. IDM_SAVE 10001. Mit "Preview" bekommen wir eine animierte Voransicht unseres Menüs. Die Keyboardfunktionen für das Menü sind in Windows fest integriert, die kommen automatisch (Alt für das Menu und Navigation mit den Pfeiltasten). Wenn wir für die Haupteinträge Buchstaben zum Aufrufen verwenden wollen, geht das mit einem "&" vor dem Buchstaben, also statt "Datei" "&Datei" oder "D&atei". Die Funktion "Accelerator" im Editor ist nicht lokalisiert, brauchen wir auch nicht. Es geht um den Hilfetext, der hinter den Menüeinträgen steht, und das können wir auch manuell mit einem "\t". So bewirkt also "Öffnen\tStrg + S" das als Hinweistext "Strg + S" angezeigt wird. Dann gibt es noch die Möglichkeit, einen Querstrich zwischen Menüeinträgen zu erzeugen, den erzeugen wir mit der Caption "-" und sonst nix. Checked sind Menüeinträge, die mit einem Haken davor erscheinen sollen, und Grayed-Einträge sind deaktiviert. Wie man das zur Laufzeit ändert, erkläre ich zusammen mit den Bitmaps, die man in den Menüs zeichnen kann.

WinTut19.jpg

Die Namen und ID's müssen dann wie gehabt in unsere Dialog.bi und die Message in der Callbackfunktion ist WM_COMMAND / BN_CLICKED wie bei Buttons auch. Wir verbinden das Menü mit unserem Fenster, indem wir den Namen des Menüs (IDR_MENU1) in der Property "Menu" bei unserem Dialog eintragen. Wenn wir Fensterklassen verwenden, können wir das auch bei der WNDCLASSEX Struktur für alle Fenster machen.

Kontextmenüs

Wenn wir bei den Menüs sind, können wir auch gleich das Kontextmenü abhandeln. Wir erzeugen dies als neues Menü in der Rescource, das auf Menuleisten-Ebene nur einen Eintrag mit der Caption "dummy" hat. Die Subeinträge sind dann die Einträge unseres Kontextmenüs. Alles wieder in die *.bi verlinken. Dann brauchen wir nur noch den Code, den man von C nach Basic übersetzt aus der MSDN direkt übernehmen kann (manchmal ist Microsoft auch mal nett!):

'If the mouse coordinates are in the client area: display the context menu
Function OnContextmenu(ByVal hWin As HWND, ByVal x As Integer, ByVal y As Integer) As BOOL
    Dim rc As RECT                  'client area of window
    Dim pt As Point = (x,y)     'location of mouse click
    Dim As HMENU hmenu, hmenuTrackPopup 'handle to the menu

    'Get the bounding rectangle of the client area
    GetClientRect(hWin,@rc)

    'Convert the mouse position to client coordinates
    ScreenToClient(hWin,@pt)

    'If the position is in the client area, display a shortcut menu
    If PtInRect(@rc,pt) Then
        ClientToScreen(hWin,@pt)

        'loads the Top-level Menu
        hmenu = LoadMenu(hInstance,Cast(ZString Ptr,IDM_CONTEXTMENU))

        'get a handle to the first subitem
        hmenuTrackPopup = GetSubMenu(hmenu,0)

        'display the menu at the mouse position
        TrackPopupMenu(hmenuTrackPopup,TPM_LEFTALIGN Or TPM_RIGHTBUTTON, pt.x, pt.y, 0, hWin, NULL)
        DestroyMenu(hmenu)
        Return TRUE
    EndIf

    Return FALSE
End Function

Aufgerufen wird die Funktion bei der WM_CONTEXTMENU-message:

        Case WM_CONTEXTMENU
            'If the mouse coordinates are in the client area, display the context menu
            If OnContextMenu(hWin, LoWord(lParam), HiWord(lParam) ) Then
                Return DefWindowProc(hWin, uMsg, wParam, lParam)
            End If

Auch wieder: kurz und schmerzlos, wenn gewusst wie.

Menüeinträge ändern: Bitmaps hinzufügen

Wie ich schon erwähnt habe, kann man existierende Menüs zur Laufzeit ändern, zum Beispiel um sie zu aktivieren oder ihren Status von "checked" auf "unchecked" zu ändern. Das geht mit der Funktion SetMenuItemInfo. Die dazugehörige MENUITEMINFO Struktur in der winuser.bi ist aber verbuggt (die letzte Zeile hbmpitem as HBITMAP fehlt). Entweder also die Definitionsdatei ändern oder schnell mal unsere eigene Struktur definieren:

Type MENUITEMINFOC
    cbSize as UINT
    fMask as UINT
    fType as UINT
    fState as UINT
    wID as UINT
    hSubMenu as HMENU
    hbmpChecked as HBITMAP
    hbmpUnchecked as HBITMAP
    dwItemData as DWORD
    dwTypeData as LPWSTR
    cch as UINT
    hbmpitem as HBITMAP
End Type

dabei definieren wir schnell noch einen HMENU für unser Menu, ein HBITMAP für die Bitmap und integrieren die Bitmap folder.bmp als BMP_FOLDER in unsere Recource, aber das hatten wir ja schon alles.

Dann packen wir das in unsere Fenster-Initialisierung (WM_INITDIALOG geht mal wieder nicht, da das Menu da noch nicht gezeichnet ist):

'get the handle of the hMain-Window menu:
hMenu=GetMenu(hMain)

'load the bitmap for the menuitem @16x16 pixels:
hBmp1=LoadImage(hInstance,Cast(ZString Ptr,BMP_FOLDER),IMAGE_BITMAP,16,16,LR_DEFAULTCOLOR)

Dim As MENUITEMINFOC mii
mii.cbSize = SizeOf(MENUITEMINFOC)

        'set Bitmap for IDM_FOLDER
        mii.fMask = MIIM_BITMAP
        mii.hbmpItem = hBmp1            'Bitmap fot the item
        SetMenuItemInfo(hMenu,IDM_FOLDER,FALSE,Cast(MENUITEMINFO Ptr,@mii) )

        'set IDM_ABOUT to Checked and Radiobutton style
        mii.fMask = MIIM_FTYPE Or MIIM_STATE
        mii.fType = MFT_RADIOCHECK
        mii.fState = MFS_CHECKED
        SetMenuItemInfo(hMenu,IDM_ABOUT,FALSE,Cast(MENUITEMINFO Ptr,@mii))

Die Funktion kann natürlich immer noch viel mehr, man könnte auch die Images für die "Checked" und "Unchecked" - Version ändern. Das wir einfach eine neue Struktur erzeugen können und die zur Funktion passt, wird richtig interessant, wenn es zu den Drag&Drop Interfaces kommt. Kurz gesagt erwartet Windows ab der mit dem Pointer übergebenen Speicherstelle die Variablen in der Reihenfolge wie sie im TYPE definiert sind - und dabei ist es im Prinzip egal, wie die Elemente oder der Type eigentlich heißen.

Der ganze Code bevölkert jetzt die Tutorial7.zip.

 

Gehe zu Seite Gehe zu Seite  1  2  3  4  5  6  7  8  9  10  11  12  13  
Zusätzliche Informationen und Funktionen
  Bearbeiten Bearbeiten  

  Versionen Versionen