Seite 1 von 1

Simple Gadget Animation mit PB520b2

Verfasst: 24.06.2013 12:13
von Bisonte
Hier mal ein Beispiel das die neuen BindEvent Befehle nutzt.
In Verbindung mit einem Timer lässt sich daraus eine Animation
auf einem Canvas realisieren, und das sogar ohne Unterbrechungen
wenn man z.B. das Fenster bewegt. Das was vorher nur mit Threads
oder komplizierten Verrenkungen möglich war...

Der linke Mausknopf im Canvas startet/stoppt die Animation...

Code: Alles auswählen

EnableExplicit

#Window = 0
#Gadget = 0
#Timer  = 1

Procedure DrawOnCanvas()
  
  Static Pos.f, Richtung
  
  If StartDrawing(CanvasOutput(#Gadget))
    
    DrawingMode(#PB_2DDrawing_Gradient)
    BackColor(#Blue):FrontColor(#Blue)
    GradientColor(Pos, RGB(199,199,255))
    LinearGradient(0,0,300,0)
    Box(0,0,300,60,0)
    DrawingMode(#PB_2DDrawing_Default|#PB_2DDrawing_Transparent)
    DrawText(10,10,"Simple GadgetAnim",0)
    
    If Richtung = 0
      pos + 0.02
    Else
      pos - 0.02
    EndIf
    
    If pos => 1
      richtung = 1
    ElseIf pos <= 0
      richtung = 0 
    EndIf
    
    StopDrawing()
  EndIf

EndProcedure
Procedure ProgramQuit()
  End
EndProcedure
Procedure CanvasButton()
  
  Static Go
  
  If Go = 0 ; Jetzt wird gestartet
    AddWindowTimer(#Window, #Timer, 10) ; <- Erstellen des Timers (nach wieviel ms neu gezeichnet werden soll)
    BindEvent(#PB_Event_Timer, @DrawOnCanvas(), #Window, #Timer) ; <- Hiermit wird der Timer mit der Zeichnungsprozedur verknüpft)
    Go = 1  
  Else ; Und nun wirds gestoppt
    UnbindEvent(#PB_Event_Timer, @DrawOnCanvas(), #Window, #Timer) ; <- Das Event wieder lösen
    RemoveWindowTimer(#Window, #Timer) ; <- und weg mit dem Timer
    Go = 0  
  EndIf
  
EndProcedure

Define Event

OpenWindow(#Window, 300, 300, 300, 60, "Test", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)

BindEvent(#PB_Event_CloseWindow, @ProgramQuit()) ; Das Fenster schliessen geht an ProgramQuit()

CanvasGadget(#Gadget, 0, 0, 300, 60)

BindGadgetEvent(#Gadget, @CanvasButton(), #PB_EventType_LeftButtonDown) ; Linker Mausknopf an Canvas knebeln.

DrawOnCanvas() ; Einmal Zeichnen damit irgendetwas da ist

Repeat
  Event = WaitWindowEvent()
ForEver

Re: Simple Gadget Animation mit PB520b2

Verfasst: 24.06.2013 12:19
von Lambda
Mit PostEvent() aus einem Thread heraus sind auch kollisionsfreie Updates möglich.

Re: Simple Gadget Animation mit PB520b2

Verfasst: 24.06.2013 12:22
von RSBasic
Cool, danke für dein Beispielcode mit dem Binden. :allright:

Re: Simple Gadget Animation mit PB520b2

Verfasst: 24.06.2013 12:40
von Bisonte
Alexi hat geschrieben:Mit PostEvent() aus einem Thread heraus sind auch kollisionsfreie Updates möglich.
Bisonte hat geschrieben:... vorher nur mit Threads oder komplizierten Verrenkungen möglich war...
nicht gelesen ? :mrgreen:

Re: Simple Gadget Animation mit PB520b2

Verfasst: 24.06.2013 14:09
von STARGÅTE
Danke für das Beispiel.
Dieser neue BindGadgetEvent()-Befehl ist also gerade für ein CustomGadget geeignet.

Sehr cool, wenn ich Zeit finde, werde ich meine Includes auf 5.20 umschreiben, denn das erleichtert ja schon die Benutzung von CustomGadgets.

Frage dazu:
Kann man an die Callbacks auch einen Parameter übergeben?
Bzw. kann man innerhalb des Callbacks auch auf EventType() zugreifen?
Wie ist die Reihenfolge bei der Abarbeitung der Callbacks? Scheinbar verdreht?

Code: Alles auswählen

OpenWindow(1, 300, 300, 300, 60, "Test", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)

Procedure A()
	Debug 1
EndProcedure
Procedure B()
	Debug 2
EndProcedure
Procedure C()
	Debug 3
EndProcedure

BindEvent(#PB_Event_CloseWindow, @A())
BindEvent(#PB_Event_CloseWindow, @B())
BindEvent(#PB_Event_CloseWindow, @C())

Repeat
  WaitWindowEvent()
ForEver

Re: Simple Gadget Animation mit PB520b2

Verfasst: 24.06.2013 14:22
von Bisonte
verdreht würd ich nicht sagen. Es hangelt sich halt von Callback zu Callback, in der Reihenfolge : First In - Last Out.
so wie es die WindowsCallbacks per Result = SetWindowLongPtr_(hWnd, #GWLP_WNDPROC, *ProcedureName) auch tun...
es wird ja jedesmal der "DefaultProc" mitgegeben, damit dieser am Ende des selbsterstellten wieder aufgerufen werden kann.

zum Eventtype :
Wenn man BindGadget() ohne Angabe des Eventtypes macht (ist ja optional) dann kann man im Callback mit EventType() arbeiten...
in meinem Beispiel oben z.B. ändere den Aufruf von BindGadget und die Prozedur CanvasButton()

Code: Alles auswählen

Procedure CanvasButton()
 
  Static Go
  
  If EventType() = #PB_EventType_LeftButtonDown
    
    If Go = 0 ; Jetzt wird gestartet
      AddWindowTimer(#Window, #Timer, 10) ; <- Erstellen des Timers (nach wieviel ms neu gezeichnet werden soll)
      BindEvent(#PB_Event_Timer, @DrawOnCanvas(), #Window, #Timer) ; <- Hiermit wird der Timer mit der Zeichnungsprozedur verknüpft)
      Go = 1 
    Else ; Und nun wirds gestoppt
      UnbindEvent(#PB_Event_Timer, @DrawOnCanvas(), #Window, #Timer) ; <- Das Event wieder lösen
      RemoveWindowTimer(#Window, #Timer) ; <- und weg mit dem Timer
      Go = 0 
    EndIf
    
  EndIf
  If EventType() = #PB_EventType_RightButtonDown
    MessageRequester("Hey","Ich sagte Linker Knopf")
  EndIf
  
EndProcedure

BindGadgetEvent(#Gadget, @CanvasButton()) ; Alle Eventtypes zum Canvas.
Allerdings sehe ich keinen Weg, dem Callback irgendetwas an Daten mitzugeben, es sei denn man reserviert sich Speicher
und hängt ihn an das Gadget ran (SetGadgetData oder SetProp_()) und liest es innerhalb des Callbacks wieder aus.

Edit: Witzigerweise stoppt nichtmal ein MessageRequester die Abbarbeitung des Timers :mrgreen:

Re: Simple Gadget Animation mit PB520b2

Verfasst: 24.06.2013 18:35
von ts-soft
Parameter: Nein
Alles was in einem normalen EventLoop ankommt, kommt auch in der Procedure an und läßt sich
genauso abfragen, also WindowEvent(), GadgetEvent(), EventType(), MenuEvent() usw.

Re: Simple Gadget Animation mit PB520b2

Verfasst: 24.06.2013 18:56
von STARGÅTE
Bisonte hat geschrieben:Edit: Witzigerweise stoppt nichtmal ein MessageRequester die Abbarbeitung des Timers :mrgreen:
Trotzdem werden die gebundenden Events nicht paralell abgearbeitet:

Code: Alles auswählen

OpenWindow(1, 300, 300, 300, 60, "Test", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)

Procedure A()
	Delay(1000)
   Debug 1
EndProcedure
Procedure B()
	Delay(1000)
   Debug 2
EndProcedure
Procedure C()
	Delay(1000)
   Debug 3
EndProcedure

BindEvent(#PB_Event_CloseWindow, @A())
BindEvent(#PB_Event_CloseWindow, @B())
BindEvent(#PB_Event_CloseWindow, @C())

Repeat
  WaitWindowEvent()
ForEver
Das Programm friert also solange bei WaitWindowEvent() ein, wie alle gebundenden Events zur abarbeitung brauchen.