OwnerDrawing: Unterschied zwischen den Versionen

Aus Wiki des Deutschsprachige Xbaseentwickler e. V.
Zur Navigation springen Zur Suche springen
(Die Seite wurde neu angelegt: „__FORCETOC__ == Einleitung == OwnerDrawing ist eine Programmtechnik, die es ermöglicht, Dinge mit Standard-XbaseParts zu machen, die man auf anderem Wege ni…“)
 
Keine Bearbeitungszusammenfassung
Zeile 8: Zeile 8:
== OwnerDrawing der Elemente in einer [[XbpMenuBar()]] ==
== OwnerDrawing der Elemente in einer [[XbpMenuBar()]] ==


Dieser Programmcode soll aus Verdeutlichung dienen. Teile hiervon stammen aus dem XbpImgMenu()-Beispiel, das Alaska mit Xbase++ ausliefert.
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_RATIO 0.6
Zeile 135: Zeile 135:
   oDlg:close := {|| WinManKill(), _QUIT()}
   oDlg:close := {|| WinManKill(), _QUIT()}
   oDlg:title := ""
   oDlg:title := ""
  oDlg:icon := 2001
   oDlg:create()
   oDlg:create()
   RootWindow(oDlg)
   RootWindow(oDlg)

Version vom 8. August 2019, 20:50 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-Slots des XbpMenuBar()-Objektes müssen vor der Ausführung von :addItem erfolgen, damit das XbpMenubar()-Objekt diese Methoden 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.