Hallo zusammen
Vielleicht gibt es so etwas bereits, aber egal...
Ich habe 3 kleine Types erstellt, mit denen man Events ähnlich wie in .NET verwenden kann. Ein Event hat beliebig viele Event-Handler die alle aufgerufen werden, sobald der Event ausgelöst wird.
Es werden sowohl Funktionen wie auch Methoden unterstützt.
Im wesentlichen erstellt man zuerst einen Event. Diesem können Handler hinzugefügt oder auch wieder entfernt werden. Und irgendwann löst man den Event aus. Alle Handler-Funktionen oder -Methoden werden aufgerufen:
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Local event:TMaxEvent = New TMaxEvent event.AddHandler(TMaxEventHandler.FuncPtr(meineFunktion)) event.AddHandler(TMaxEventHandler.MethodPtr(meinObjekt, "meineMethode"))
event.AddHandlerFuncPtr(meineFunktion) event.AddHandlerMethodPtr(meinObjekt, "meineMethode")
event.Raise(quellObjekt, eventArgumente)
Hier der Code:
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Type TMaxEvent Field _handlers:TList = New TList
Method AddHandler(handler:TMaxEventHandler) If Not _handlers.Contains(handler) Then _handlers.AddLast(handler) End Method
Method AddHandlerFuncPtr:TMaxEventHandler(funcPtr(source:Object, e:TMaxEventArgs)) Local handler:TMaxEventHandler = TMaxEventHandler.FuncPtr(funcPtr) If handler <> Null Then _handlers.AddLast(handler) Return handler End Method
Method AddHandlerMethodPtr:TMaxEventHandler(obj:Object, methodName:String) Local handler:TMaxEventHandler = TMaxEventHandler.MethodPtr(obj, methodName) If handler <> Null Then _handlers.AddLast(handler) Return handler End Method
Method RemoveHandler(handler:TMaxEventHandler) _handlers.Remove(handler) End Method
Method Raise(source:Object, e:TMaxEventArgs) For Local handler:TMaxEventHandler = EachIn _handlers handler.Invoke(source, e) Next End Method End Type
Type TMaxEventHandler Field _func(source:Object, e:TMaxEventArgs) Field _obj:Object Field _method:TMethod
Function FuncPtr:TMaxEventHandler(func(source:Object, e:TMaxEventArgs)) If func = Null Then Return Null Local handler:TMaxEventHandler = New TMaxEventHandler handler._func = func Return handler End Function
Function MethodPtr:TMaxEventHandler(obj:Object, methodName:String) If obj = Null Or methodName = Null Or methodName = "" Then Return Null
Local t:TTypeId = TTypeId.ForObject(obj) If t = Null Then Return Null
Local m:TMethod = t.FindMethod(methodName) If m = Null Then Return Null
Local args:TTypeId[] = m.ArgTypes() If args.Length <> 2 Then Return Null
Local tObj:TTypeId = TTypeId.ForName("Object") If args[0].Name() <> "Object" And Not args[0].ExtendsType(tObj) Then Return Null Local tArgs:TTypeId = TTypeId.ForName("TMaxEventArgs") If tArgs = Null Then Return Null If args[1].Name() <> "TMaxEventArgs" And Not args[1].ExtendsType(tArgs) Then Return Null Local handler:TMaxEventHandler = New TMaxEventHandler handler._obj = obj handler._method = m Return handler End Function
Method Invoke(source:Object, e:TMaxEventArgs) If _func <> Null Then _func(source, e) ElseIf _obj <> Null And _method <> Null Then Try _method.Invoke(_obj, [source, Object(e)]) Catch ex:Object DebugLog("Die Methode " + _method.Name() + " in Type " + _method._selfTypeId.Name() + .. " konnte vom EventHandler nicht aufgerufen werden, da vermutlich die Argument-Typen des EventHandlers nicht mit den~r~n" + .. "uebergebenen Parametern bei Raise(...) uebereinstimmen. Wenn eine Methode mit abgeleiteten Argumenttypen verwendet wird" + .. " muessen bei Raise(...) auch Objekte des~r~nentsprechenden Typs uebergeben werden. Ansonsten sollte die Grundform:" + .. " MethodenName(source:Object, e:TMaxEventArgs) verwendet werden.") End Try End If End Method End Type
Type TMaxEventArgs End Type
Und noch ein etwas ausführlicheres Beispiel mit einem Button:
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Graphics 800, 600, 0, 0
Local test:TTest = New TTest
Local button:TButton = TButton.Create(200, 200, 150, 30, "Klick mich!")
button.Click.AddHandlerFuncPtr(button_Click) button.Click.AddHandlerMethodPtr(test, "ButtonClicked")
Local timer:TTimer = TTimer.Create(60) Repeat Cls
button.Update() button.Draw() Flip 0 timer.Wait() Until AppTerminate() Or KeyHit(KEY_ESCAPE)
EndGraphics End
Function button_Click(source:Object, eargs:TMaxEventArgs) Local e:TClickEventArgs = TClickEventArgs(eargs) DebugLog("1: Button wurde angeklickt bei " + e.x + ", " + e.y + " mit Button Nr. " + e.button) End Function
Type TTest Method ButtonClicked(source:Object, e:TClickEventArgs) DebugLog("2: Button wurde angeklickt bei " + e.x + ", " + e.y + " mit Button Nr. " + e.button) End Method End Type
Type TClickEventArgs Extends TMaxEventArgs Field x:Float, y:Float Field button:Int End Type
Type TButton Field x:Float, y:Float Field w:Float, h:Float Field text:String
Field Click:TMaxEvent = New TMaxEvent
Function Create:TButton(x:Float, y:Float, w:Float, h:Float, text:String) Local b:TButton = New TButton b.x = x; b.y = y b.w = w; b.h = h b.text = text Return b End Function Method Update() Local mx:Int = MouseX() Local my:Int = MouseY() If MouseHit(1) If mx > x And mx < x + w And my > y And my < y + h Then Local e:TClickEventArgs = New TClickEventArgs e.x = mx e.y = my e.button = 1 Click.Raise(Self, e) End If EndIf End Method Method Draw() DrawRect(x, y, w, h) SetColor(0, 0, 0) DrawRect(x + 2, y + 2, w - 4, h - 4) SetColor(255, 255, 255) DrawText(text, x + (w - TextWidth(text)) * 0.5, y + (h - TextHeight(text)) * 0.5) End Method End Type
|