OwnerDrawing: Unterschied zwischen den Versionen
Georg (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
Georg (Diskussion | Beiträge) KKeine Bearbeitungszusammenfassung |
||
Zeile 168: | Zeile 168: | ||
Wenn das Menü angezeigt wird, wird für jedes Item, das mit dem Parameter XBPMENUBAR_MIA_OWNERDRAW als viertem Parameter definiert wurde, die in :drawItem definierte Funktion ausgeführt. In diesem Beispiel wird lediglich der normale Text in den als Parameter übergebenen [[XbpPresSpace()]] ausgegeben. Denkbar sind hier (wie im Alaska-Beispiel) die Anzeige von Icons, oder verschiedenfarbige Hintergründe für die einzelnen Menü-Einträge. | Wenn das Menü angezeigt wird, wird für jedes Item, das mit dem Parameter XBPMENUBAR_MIA_OWNERDRAW als viertem Parameter definiert wurde, die in :drawItem definierte Funktion ausgeführt. In diesem Beispiel wird lediglich der normale Text in den als Parameter übergebenen [[XbpPresSpace()]] ausgegeben. Denkbar sind hier (wie im Alaska-Beispiel) die Anzeige von Icons, oder verschiedenfarbige Hintergründe für die einzelnen Menü-Einträge. | ||
=== Verwendung einer anderen Schriftart === | |||
Varieren wir das Beispiel nun ein wenig. :measureItem verwendet den Standard-Font, den der Windows-Desktop verwendet (da dies auch der Font ist, mit dem die Captions der Menü-Einträge dargestellt werden). | |||
Dafür müssen wir erst einmal im :measureItem-Slot eine andere Schriftart zuweisen, damit wir deren Dimension ermitteln: | |||
oPS := AppDesktop():lockPS() | |||
oFnt := GraSetFont( oPS ) | |||
oFont := XbpFont():new() | |||
oFont:familyName := "Courier New" | |||
oFont:compoundName := "Courier New.12 Bold" | |||
oFont:create() | |||
GraSetFont(oPS, oFont) | |||
Ich habe hier die Erzeugung eines weiteren [[XbpFont()]]-Objektes eingefügt, dem ich als Schriftart "Courier New" zugewiesen habe. Dem [[XbpPresSpace()]] weise ich nun diese Schriftart zu, so dass die Ermittlung der Caption-Grösse sich auf die Schriftart "Courier New" mit 12 Pixel Höhe bezieht. | |||
Als weiteren Schritt muss ich diese Zuweisung auch im :drawitem-Slot ausführen lassen: | |||
oFont := XbpFont():new() | |||
oFont:familyName := "Courier New" | |||
oFont:compoundName := "Courier New.12 Bold" | |||
oFont:create() | |||
IF BAnd(aInfo[3], XBP_DRAWSTATE_SELECTED) != 0 | |||
aAAttrs[GRA_AA_COLOR] := XBPSYSCLR_WINDOW | |||
ELSE | |||
aAAttrs[GRA_AA_COLOR] := XBPSYSCLR_3DFACE | |||
ENDIF | |||
GraSetAttrArea( oPS, aAAttrs ) | |||
GraSetFont(oPS, oFont) | |||
Durch die [[GraSetFont()]]-Zuweisung verwendet der [[XbpPresSpace()]] nur "Courier New" mit 12 Pixel Höhe als Schriftart für die Darstellung der Menü-Captions. | |||
Analog lässt sich auch ein anderer Hintergrund definieren, oder (wie im Alaska-Beispiel gezeigt), den Menü-Einträge auch ein Icon zuweisen. |
Version vom 9. August 2019, 21:43 Uhr
Einleitung
OwnerDrawing ist eine Programmtechnik, die es ermöglicht, Dinge mit Standard-XbaseParts zu machen, die man auf anderem Wege nicht machen kann. Grob vereinfacht bietet OwnerDrawing die Möglichkeit, XbaseParts (oder Teile davon) von Windows (= Standard) oder durch das eigene Programm zeichnen zu lassen. Ein Beispiel wäre eine optische Hervorhebung von Zellen in einem Browse.
OwnerDrawing der Elemente in einer XbpMenuBar()
Dieser Programmcode soll aus Verdeutlichung dienen. Teile hiervon stammen aus dem XbpImgMenu()-Beispiel, das Alaska mit Xbase++ ausliefert. Für dieses Beispiel wurde der Code grob vereinfacht.
#DEFINE SCREEN_RATIO 0.6 #DEFINE SCREEN_MIN_X 800 #DEFINE SCREEN_MIN_Y 600 #INCLUDE "AppEvent.CH" #INCLUDE "NLS.CH" #INCLUDE "Xbp.CH" #INCLUDE "GRA.CH" #DEFINE ITEM_SPACING 5 FUNCTION Main() Local mp1, mp2 Local nEvent Local oXbp GenerateMenu() SetAppFocus(SetAppWindow()) nEvent := xbe_None oXbp := mp1 := mp2 := nEvent WHILE nEvent <> xbeP_Close nEvent := AppEvent(@mp1, @mp2, @oXbp) oXbp:handleEvent(nEvent, mp1, mp2) END RETURN (.T.) FUNCTION GenerateMenu() Local oBar, oSub, oDlg oDlg := RootWindow() oBar := oDlg:menuBar():new():create() oBar:measureItem := {|nItem,aDims,self| MeasureMenubarItem(oDlg,self,nItem,aDims) } oBar:drawItem := {|oPS,aInfo,self | DrawMenubarItem(oDlg,self,oPS,aInfo) } oBar:addItem({"Fibu", , , XBPMENUBAR_MIA_OWNERDRAW}) oBar:addItem({"Daten", , , XBPMENUBAR_MIA_OWNERDRAW}) oBar:addItem({"Fenster", , , XBPMENUBAR_MIA_OWNERDRAW}) oBar:addItem({"Exit", , , XBPMENUBAR_MIA_OWNERDRAW}) RETURN (.T.) FUNCTION MeasureMenubarItem(oDlg, oBar, nItem, aDims) LOCAL oPS LOCAL cStr LOCAL cTmp LOCAL oFnt LOCAL aBox oPS := AppDesktop():lockPS() oFnt := GraSetFont( oPS ) cStr := oBar:getItem(nItem)[1] cTmp := StrTran( cStr, "~" ) aBox := GraQueryTextBox( oPS, cTmp ) aDims[1] := aBox[3,1] - aBox[2,1] aDims[2] := oFnt:width + ITEM_SPACING *2 AppDesktop():unlockPS() RETURN oBar FUNCTION DrawMenuBarItem(oDlg, oBar, oPS, aInfo) LOCAL aItem := oBar:getItem( aInfo[1] ) LOCAL aSAttrs := Array( GRA_AS_COUNT ) LOCAL aAAttrs := Array( GRA_AA_COUNT) IF BAnd(aInfo[3], XBP_DRAWSTATE_SELECTED) != 0 aAAttrs[GRA_AA_COLOR] := XBPSYSCLR_WINDOW ELSE aAAttrs[GRA_AA_COLOR] := XBPSYSCLR_3DFACE ENDIF GraSetAttrArea( oPS, aAAttrs ) // Pruefen, ob die Anwendung unter windows XP // mit eingeschalteten Windows Themes ausgefuehrt // wird. Falls ja, Hintergrundrechteck anpassen // (Separator). IF IsThemeActive(.F.) == .T. GraBox( oPS, {aInfo[4][1],aInfo[4][2]+1},{aInfo[4][3],aInfo[4][4]}, GRA_FILL ) ELSE GraBox( oPS, {aInfo[4][1],aInfo[4][2]}, {aInfo[4][3],aInfo[4][4]}, GRA_FILL ) ENDIF aSAttrs[GRA_AS_VERTALIGN] := GRA_VALIGN_HALF GraSetAttrString( oPS, aSAttrs ) oPS:DrawCaptionStr( {aInfo[4][1] + ITEM_SPACING,aInfo[4][2]}, {aInfo[4][3],aInfo[4][4]}, aItem[1]) RETURN oBar FUNCTION DBESys() // keine DBE erforderlich RETURN (.T.) FUNCTION AppSys() Local aSize, oDlg, aPos[2], aSizeNew[2], nI SetLocale(NLS_ICURRENCYEURO, "1") SET CHARSET TO ANSI SET DATE GERMAN SET CENTURY ON aSize := AppDesktop():currentSize() FOR nI := 1 TO 2 aSizeNew[nI] := Int(aSize[nI] * SCREEN_RATIO) NEXT IF aSizeNew[1] < SCREEN_MIN_X aSizeNew[1] := SCREEN_MIN_X ENDIF IF aSizeNew[2] < SCREEN_MIN_Y aSizeNew[2] := SCREEN_MIN_Y ENDIF aPos[1] := Int((aSize[1] - aSizeNew[1]) / 2) aPos[2] := Int((aSize[2] - aSizeNew[2]) / 2) oDlg := XbpDialog():new(AppDesktop(), AppDesktop(), aPos, aSizeNew, , .F.) oDlg:sysmenu := .T. oDlg:hideButton := .T. oDlg:taskList := .T. oDlg:close := {|| WinManKill(), _QUIT()} oDlg:title := "" oDlg:create() RootWindow(oDlg) oDlg:setTitle(GetProgramTitle()) oDlg:drawingArea:scrollBars := XBP_SCROLLBAR_VERT oDlg:show() SetAppWindow(oDlg) RETURN (.T.) FUNCTION RootWindow(oDlg) Static oStatic IF oDlg <> NIL oStatic := oDlg ENDIF IF oStatic = NIL ConfirmBox(, "Fehler", "Programm nicht richtig geladen", XBPMB_CRITICAL, XBPMB_OK) QUIT ENDIF RETURN (oStatic) FUNCTION WinManKill() RETURN (.T.) FUNCTION GetProgramTitle() Local cTitle := "Ein Test-Programm" RETURN (cTitle)
Wichtig ist die Reihenfolge der Zuweisungen. Die Besetzung der :measureItem und :drawItem-CallbackSlots des XbpMenuBar()-Objektes müssen vor der Ausführung von :addItem erfolgen, damit das XbpMenubar()-Objekt diese Callbacks kennt und für jedes Item ausführen kann.
In dem Slot :measureItem wird ermittelt, wie gross ein Menü-Eintrag ist. Das Ergebnis wird im Format {Länge, Höhe} über den Aufruf-Parameter aDim zurückgeliefert, nicht über den Wert in der RETURN-Anweisung!
Wenn das Menü angezeigt wird, wird für jedes Item, das mit dem Parameter XBPMENUBAR_MIA_OWNERDRAW als viertem Parameter definiert wurde, die in :drawItem definierte Funktion ausgeführt. In diesem Beispiel wird lediglich der normale Text in den als Parameter übergebenen XbpPresSpace() ausgegeben. Denkbar sind hier (wie im Alaska-Beispiel) die Anzeige von Icons, oder verschiedenfarbige Hintergründe für die einzelnen Menü-Einträge.
Verwendung einer anderen Schriftart
Varieren wir das Beispiel nun ein wenig. :measureItem verwendet den Standard-Font, den der Windows-Desktop verwendet (da dies auch der Font ist, mit dem die Captions der Menü-Einträge dargestellt werden).
Dafür müssen wir erst einmal im :measureItem-Slot eine andere Schriftart zuweisen, damit wir deren Dimension ermitteln:
oPS := AppDesktop():lockPS() oFnt := GraSetFont( oPS )
oFont := XbpFont():new() oFont:familyName := "Courier New" oFont:compoundName := "Courier New.12 Bold" oFont:create()
GraSetFont(oPS, oFont)
Ich habe hier die Erzeugung eines weiteren XbpFont()-Objektes eingefügt, dem ich als Schriftart "Courier New" zugewiesen habe. Dem XbpPresSpace() weise ich nun diese Schriftart zu, so dass die Ermittlung der Caption-Grösse sich auf die Schriftart "Courier New" mit 12 Pixel Höhe bezieht.
Als weiteren Schritt muss ich diese Zuweisung auch im :drawitem-Slot ausführen lassen:
oFont := XbpFont():new() oFont:familyName := "Courier New" oFont:compoundName := "Courier New.12 Bold" oFont:create()
IF BAnd(aInfo[3], XBP_DRAWSTATE_SELECTED) != 0 aAAttrs[GRA_AA_COLOR] := XBPSYSCLR_WINDOW ELSE aAAttrs[GRA_AA_COLOR] := XBPSYSCLR_3DFACE ENDIF
GraSetAttrArea( oPS, aAAttrs ) GraSetFont(oPS, oFont)
Durch die GraSetFont()-Zuweisung verwendet der XbpPresSpace() nur "Courier New" mit 12 Pixel Höhe als Schriftart für die Darstellung der Menü-Captions.
Analog lässt sich auch ein anderer Hintergrund definieren, oder (wie im Alaska-Beispiel gezeigt), den Menü-Einträge auch ein Icon zuweisen.