Ich brauche noch mal Eure Hilfe, sonst krieg ich hier nen Koller.
Was ich eigentlich erreichen möchte:
- Einen Button, dessen Aussehen ich mit zwei Images (mit Transparenz) bestimmen kann (gedrückter und ungedrückter Zustand)
- Die Images des Buttons sollen den Untergrund nicht zerstören- auch wenn die Images für gedrückt und ungedrückt verschiedene Formen haben (kann man sicher durch Zwischenspeicherung des Untergrunds des Buttons erreichen)
- Der Button soll nur eine CLICK Message erzeugen, wenn die Maus in einem
nicht-transparenten Bereich des Images geklickt wurde. Auch soll der Button nur als gedrückt gezeichnet werden, wenn die Maus im
nicht-transparenten Bereich geklickt wurde.
Stellt Euch einfach einen kreisförmigen Button vor. Als "gedrückt" gilt er nur, wenn innerhalb des Kreises geklickt wurde.
- Er soll bei dauerhaft gedrückter Maustatse so reagieren, wie ein "normaler" Button. Also sobald ich mit der Maus aus dem Kreis herausfahre, soll er wieder nichtgedrückt erscheinen, und wenn ich wieder hereinfahre, dann soll er wieder als gedrückt erscheinen. Eine CLICK-Message soll erst nach Loslassen des Mausbuttons generiert werden (und auch nur dann, wenn sich der Mauszeiger dabei im
nicht-transparenten Bereich befindet).
- Der Button soll keine Doppelklicks auswerten.
Nun, daß das ganze solch ein Fiasko wird, hatte ich nicht erwartet.
Schon blöd, wenn man die internen Windowszusammenhänge nicht gut kennt.
Ich habe nun mehrere Ansätze durchprobiert, bin aber zu keiner zufriedenstellenden Lösung gekommen.
Vielleicht hab ich eine völlig falsche Herangehensweise - keine Ahnung. Ich hoffe jetzt auf die Erfahrung der Windows-Cracks unter euch, um die richtigen Denkanstöße zu bekommen.
Mein bisheriger Stand ist folgender:
- Es wird ein PB-Buttongadget mit der Option #BS_OWNERDRAW genutzt.
- Die Imagehandles werden mittels SetProp_()/GetProp_() an den Eigenschaften des jeweiligen Gadgets zwischengespeichert, und dadurch für den WindowCallBack verfügbar gemacht (also keine globalen Variablen).
- Ein "ControlCallBack" pro Gadget ist ebenfalls nötig, um die mittels SetProp_() gesetzen Eigenschaften beim destroyen des Gadegts wieder zu entfernen.
- Im Fenstercallback/#WM_DRAW - Abschnitt wird die aktuelle Mausposition innerhalb des Gadgets berechnet und mit diesen Koordinaten der Tranzparentwert des darunter liegenden Pixels ermittelt (AlphaValue).
Wo ich gerade dran scheitere ist, daß der Button nicht gedrückt sein darf, wenn die Maus in einen transparenten Bereich klickt.
Da ich einen normalen Button als Gadget benutze, gilt er leider schon als gedrückt, wenn die Maus irgendwo innerhalb des Gadget-Rects klickt. Also müsste ich an dieser Stelle verhindern, daß -welche Prozedure auch immer dafür verantwortlich ist- in diesem Fall kein CLICK-Event erzeugt wird.
Das kommt mir ehrlich gesagt alles ziemlich gewürgt und gekrampft vor.
Hat jemand von Euch schon einmal ein völlig eigenes Customgadget unter Windows programmiert? Das muß doch geschmeidiger gehen?
Wenn ich daran denke, daß ich außer diesem popeligen CustomButtonGadget noch ein viel komplexeres Gadget benötige zur Darstellung einer Waveform inkl. Scroll- und Zoombuttons, wird mir ganz anders (da komme ich in Zukunft bestimmt nochmal auf Euch zurück).
Hier ist der Code den ich bisher erstellt habe:
Code: Alles auswählen
EnableExplicit
Procedure.i ButtonImageCustomCallback(iWindowID, iMessage, wParam, lParam)
; +-----------------------------------------------------------------
; |Description : CallbackProzedur des Imagebuttons
; |Arguments :
; |Result :
; +-----------------------------------------------------------------
Protected iOldWindowCallback.i = GetProp_(iWindowID, "bic_OldCallback")
Select iMessage
Case #WM_NCDESTROY
RemoveProp_(iWindowID, "bic_OldCallback")
RemoveProp_(iWindowID, "bic_Image1")
RemoveProp_(iWindowID, "bic_Image2")
RemoveProp_(iWindowID, "bic_CurrentImage")
RemoveProp_(iWindowID, "bic_ParentWindow")
Debug "Destroy"
EndSelect
ProcedureReturn CallWindowProc_(iOldWindowCallback, iWindowID, iMessage, wParam, lParam)
EndProcedure
Procedure.i WindowCallback(iWindowID, iMessage, wParam, lParam)
; +-----------------------------------------------------------------
; |Description : CallbackProzedur des übergeordneten Fensters
; |Arguments :
; |Result :
; +-----------------------------------------------------------------
Protected stCursorPos.POINT
Protected *stDrawitem.DRAWITEMSTRUCT
Protected iAlphaValue.i
Protected iImage1.i
Protected iImage2.i
Protected iCurrentImage.i
Protected iParentWindow.i
Select iMessage
Case #WM_DRAWITEM
*stDrawitem = lParam
If *stDrawitem\CtlType = #ODT_BUTTON
iImage1 = GetProp_(*stDrawitem\hwndItem, "bic_Image1")
iImage2 = GetProp_(*stDrawitem\hwndItem, "bic_Image2")
iCurrentImage = GetProp_(*stDrawitem\hwndItem, "bic_CurrentImage")
iParentWindow = GetProp_(*stDrawitem\hwndItem, "bic_ParentWindow")
stCursorPos\x = WindowMouseX(GetDlgCtrlID_(iParentWindow)) - GadgetX(*stDrawitem\CtlID)
stCursorPos\y = WindowMouseY(GetDlgCtrlID_(iParentWindow)) - GadgetY(*stDrawitem\CtlID)
Debug Str(stCursorPos\x) + " " + Str(stCursorPos\y)
If stCursorPos\x & $FF < GadgetWidth(*stDrawitem\CtlID) And stCursorPos\y & $FF < GadgetHeight(*stDrawitem\CtlID) And iCurrentImage > 0
StartDrawing(ImageOutput(iCurrentImage))
DrawingMode(#PB_2DDrawing_AlphaChannel)
iAlphaValue = Alpha(Point(stCursorPos\x, stCursorPos\y))
Debug "Alpha: " + Hex(iAlphaValue)
StopDrawing()
EndIf
Select *stDrawitem\itemState
Case #ODS_FOCUS | #ODS_SELECTED
If iCurrentImage <> iImage2
StartDrawing(WindowOutput(GetDlgCtrlID_(iParentWindow)))
;DrawingMode(#PB_2DDrawing_AlphaChannel)
DrawAlphaImage(ImageID(iImage2), GadgetX(*stDrawitem\CtlID), GadgetY(*stDrawitem\CtlID))
StopDrawing()
SetProp_(*stDrawitem\hwndItem, "bic_CurrentImage", iImage2)
;Debug 1
EndIf
Case #ODS_FOCUS
If iCurrentImage <> iImage1
StartDrawing(WindowOutput(GetDlgCtrlID_(iParentWindow)))
;DrawingMode(#PB_2DDrawing_AlphaChannel)
DrawAlphaImage(ImageID(iImage1), GadgetX(*stDrawitem\CtlID), GadgetY(*stDrawitem\CtlID))
StopDrawing()
SetProp_(*stDrawitem\hwndItem, "bic_CurrentImage", iImage1)
;Debug 2
EndIf
Default
If iCurrentImage <> iImage1
StartDrawing(WindowOutput(GetDlgCtrlID_(iParentWindow)))
;DrawingMode(#PB_2DDrawing_AlphaChannel)
DrawAlphaImage(ImageID(iImage1), GadgetX(*stDrawitem\CtlID), GadgetY(*stDrawitem\CtlID))
StopDrawing()
SetProp_(*stDrawitem\hwndItem, "bic_CurrentImage", iImage1)
;Debug 3
EndIf
EndSelect
EndIf
EndSelect
ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure
Procedure.i ButtonImageCustom(iGadgetNr.i, iPosX.i, iPosY.i, iWidth.i, iHeight.i, iText.s, iFlags, iImage1.i, iImage2.i)
; +-----------------------------------------------------------------
; |Description : Darstellen eines eigenen Imagebuttons ohne störenden Rand (ImageGadget)
; |Arguments : iGadgetNr : Feste Nummer oder #PB_Any
; | : iPosX : X Position des Gadgets
; | : iPosY : Y Position des Gadgets
; | : iWidth : Breite des Gadgets
; | : iHeight : Höhe des Gadgets
; | : iText : For future use
; | : iFlags : Flags eines normalen ImageGadgets
; | : iImage1 : Image-Nummer (nicht ID) des ungedrückten ImageButtons
; | : iImage2 : Image-Nummer (nicht ID) des gedrückten ImageButtons
; |Result : ID des neuen Gadgets
; +-----------------------------------------------------------------
Protected iGadgetID.i
If iGadgetNr.i = #PB_Any
;iGadgetID = ImageGadget(#PB_Any, iPosX, iPosY, iWidth, iHeight, ImageID(iImage1), iFlags)
iGadgetID = ButtonGadget(#PB_Any, iPosX, iPosY, iWidth, iHeight, "", #BS_OWNERDRAW)
iGadgetID = GadgetID(iGadgetID)
Else
;iGadgetID = ImageGadget(iGadgetNr, iPosX, iPosY, iWidth, iHeight, ImageID(iImage1), iFlags)
iGadgetID = ButtonGadget(iGadgetNr, iPosX, iPosY, iWidth, iHeight, "", #BS_OWNERDRAW)
EndIf
SetProp_(iGadgetID, "bic_OldCallback", SetWindowLongPtr_(iGadgetID, #GWL_WNDPROC, @ButtonImageCustomCallback()))
SetProp_(iGadgetID, "bic_Image1", iImage1)
SetProp_(iGadgetID, "bic_Image2", iImage2)
SetProp_(iGadgetID, "bic_CurrentImage", 0)
SetProp_(iGadgetID, "bic_ParentWindow", GetParent_(iGadgetID))
; Doppelklicks verhindern
SetClassLongPtr_(iGadgetID, #GCL_STYLE, GetClassLongPtr_(iGadgetID, #GCL_STYLE) &~ #CS_DBLCLKS)
ProcedureReturn iGadgetID
EndProcedure
Global iEvent.i, iEventType.i, iEventWindow.i, iEventwParam.i, iEventlParam.i, iEventGadget.i, iEventMenu.i
Global iButtonImage1.i, iButtonImage2.i
If OpenWindow(0, 300, 200, 220, 60, "Custom Button Test", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
SetWindowCallback(@WindowCallback())
iButtonImage1 = LoadImage(#PB_Any, "alphabutton1.bmp")
iButtonImage2 = LoadImage(#PB_Any, "alphabutton2.bmp")
ButtonImageCustom(1, 10, 10, 32, 32, "Test",0, iButtonImage1, iButtonImage2)
ButtonImageCustom(#PB_Any, 60, 10, 32, 32, "Test2", 0, iButtonImage2, iButtonImage1)
ButtonGadget(2, 120, 10, 80, 40, "Normaler Button")
Repeat
iEvent = WaitWindowEvent(25)
iEventType = EventType()
iEventWindow = EventWindow()
iEventwParam = EventwParam()
iEventlParam = EventlParam()
iEventGadget = EventGadget()
iEventMenu = EventMenu()
Until iEvent = #PB_Event_CloseWindow
CloseWindow(0)
EndIf
Und hier nochmal die BMPs inkl. Code:
BMP Dateien
Ich bin für konstruktive Hinweise dankbar.