ich versuche mir aktuell ein komplexes, eigenes Gadget mittels des Canvas Gadgets zu schreiben.
Es soll nach dem Erzeugen mit MeinGadget() auch wieder entfernbar sein. Und zwar mit der PB-eigenen Prozedur FreeGadget(MeinGadget) .
Mein Anspruch ist, dass die Verwendung sich möglichst nahtlos in die vorhandene Logik der PB Gadgets einfügt. Auch was die Eventbearbeitung angeht.
Die bisherigen Beispiele, die ich im Forum gefunden habe, sind entweder nicht auf dem Canvas basierend oder aber nutzen eigene Prozeduren zum Freigeben der Instanzen und des Speichers. Das wäre dann z.B. FreeMeinGadget() statt des PB-Befehls FreeGadget().
Bei der Bearbeitung von Events gehen die Beispiele so vor, dass im Eventloop nur geprüft wird, ob das jeweilige Canvasgadget (auf welchem das eigene Gadget aufbaut) einen Event erzeugt hat.
Danach müssen dann die Details mit einem weiteren Prozeduraufruf ermittelt werden (z.B. MeinGadget_Getevent(), welches dann weitere Eventkonstanten liefert. Bei einem Drehknopf z.B. ein Event "Knopf wurde gedreht") Ich würde mein eigenes Gadget gern direkt eigene Events in die PB Eventqeue legen. So dass der PB Befehl EventType() im Beispiel oben ein #MEINGADGET_KNOBDRAGGED liefert.
Leider scheitert es schon bei den ersten Tests mit einer WindowsCallback Prozedur.
Anbei ist ein Testcode, der ein Fenster öffnet und ein eigenes Gadget unter Verwendung eines Canvasgadgets und einer Callback Prozedur erzeugt.
Mir ist bewusst, dass man zur Verwaltung von verschiedenen Gadgetinstanzen weitere Struktureinträge benötigt und diese Daten pro Instanz in einem eigenen Memorybuffer speichert, deren Adresse man am besten mittels SetGadgetData() an das Canvasgadget heftet.
Das habe ich bei diesem Testcode weggelassen, da es mir erstmal um die richtige Anwendung des Callbacks geht. Ich habe leider keine C/C++/C# oder sonstigen "Mainstreamprogrammiersprachenkenntnisse", daher wohl auch das fehlende Verständnis speziell in diesem Bereich.
Folgende Fragen habe ich bzgl. des Testcodes:
- Mit aktiver Callbackprozedur wird das Canvasgadget nicht mehr neu gezeichnet, wenn man das Fenster verkleinert/vergrößert und damit Teile des Gadgets verdeckt. Ich dachte die Bearbeitung der Gadgetevents durch PureBasic wird weiterhin durchgeführt, wenn der Rückgabewert #PB_ProcessPureBasicEvents lautet.
Nachtrag:
Hier habe ich folgende Lösung gefunden:
Statt iResult = #PB_ProcessPureBasicEvents am Anfang der Prozedur
nehme man iResult = DefWindowProc_(iWindow, iMessage, wParam, lParam) vor dem ProcedureReturn
Dann wird zumindest das Canvasgadget (die Ränder) neu gezeichnet. Der selbst gezeichnete Inhalt wird allerdings damit nicht wieder restauriert.
- Der Teil "Case #WM_LBUTTONUP" im der Callbackprozedur wird nicht ausgeführt, wenn ich in das Gadget klicke. Warum? Gegenprobe: Wenn ich das Fenster schließe und das Canvasgadget durch PureBasic entfernt wird, dann wir der Teil "Case #WM_NCDESTROY" sehr wohl ausgeführt.
- Ist es die korrekte Art einen Callback wieder zu entfernen, wenn man dies innerhalb der betreffenden Callbackprozedur bei Auftreten von #WM_NCDESTROY tut?
Code: Alles auswählen
Case #WM_NCDESTROY
SetWindowCallback(0, Settings\iGadgetNr) ; Callback wird wieder entfernt

Bei einem Mausklick in eines der Zahlenfelder soll das Gadget eigenständig die Tastatureingabe von Ziffern bzw. die Auswahl von Ziffern aus einer aufklappenden Liste managen.
Hier ist mir auch nicht nicht ganz klar wie man das realisiert, denn im Grunde benötigt das Gadget selbst einen Eventloop und muss auf die Eingaben reagieren.
Bei dem Beispiel mit der Eingabe soll das Gadget dann ein "Es wurde ein Feld geändert"-Message in die PB-Eventqeue legen und kein "Linke Masutaste wurde gedrückt".
Über weitere Hinweise und Korrekturen würde ich mich freuen.
Testcode:
Code: Alles auswählen
Structure MeinGadget_Attributes
iGadgetNr.i
iGadgetInitalized.i
EndStructure
Global Settings.MeinGadget_Attributes
Procedure _WindowProcCallback(iWindow.i, iMessage.i, wParam.i, lParam.i)
Protected iResult.i
iResult = #PB_ProcessPureBasicEvents
Select iMessage
Case #WM_LBUTTONUP
Debug "#WM_LBUTTONUP"
Case #WM_NCDESTROY
Debug "WM_NCDESTROY"
SetWindowCallback(0, Settings\iGadgetNr)
EndSelect
ProcedureReturn iResult
EndProcedure
Procedure _DrawGadget()
If Settings\iGadgetInitalized = 1
If StartDrawing(CanvasOutput(Settings\iGadgetNr))
Box(0, 0, 100, 100, $FF8844)
DrawText(10, 10, "Test", $FFFFFF, $FF8844)
StopDrawing()
EndIf
EndIf
EndProcedure
Procedure.i MeinGadget(iGadgetNr, x.i, y.i)
If iGadgetNr = #PB_Any
Settings\iGadgetNr = CanvasGadget(#PB_Any, x, y, 100, 100, #PB_Canvas_Border)
Else
Settings\iGadgetNr = CanvasGadget(iGadgetNr, x, y, 100, 100, #PB_Canvas_Border)
EndIf
If Settings\iGadgetNr <> 0 And Settings\iGadgetInitalized = 0
Settings\iGadgetInitalized = 1
_DrawGadget()
SetWindowCallback(@_WindowProcCallback(), Settings\iGadgetNr)
EndIf
ProcedureReturn Settings\iGadgetNr
EndProcedure
If OpenWindow(0, 0, 0, 200, 200, "Test", #PB_Window_ScreenCentered | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window3D_SizeGadget)
MeinGadget(#PB_Any, 40, 40)
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
End
EndSelect
ForEver
EndIf