Events system
Monkey Forums/Monkey Programming/Events system
| ||
I've been using my own events system for Jungle Gui. While I think it is a very solid and easy to use system, it has the problem to rely on Reflection and increasing too much compilation time on Monkey. Also, method correctness is solved at runtime, wich is not as nice as it would be by using Delegates. In my ideal world, Monkey would have Delegates, and we could just add and remove method references to a list, and invoke them later, without having to use reflection, but that's not possible, and I supose it's not in Mark's plans to add this functionality anytime soon. We could get something *similar* by manually using interfaces, but that's not dynamic. You cannot decide which method to be called at any time, it's always the interface-defined method, And also, any single class that handles the same event for different objects need to select which is the sender object before performing its actions, and that generates very dirty code (a la Java). I really dislike using interfaces to workaround the lack of delegates. Java, at last, allows the creation of inner classes to make this a bit better (I still dislike it, but at last, this is something). So, all in all, Does anybody have a good implementation of events that solves my scenario without using Reflection? EDIT: I see that the delegates system could be easily implemented into Monkey but I supose Mark does not want to make such this change into the language, Anyway, if there's any interest, my idea of implementation is here: http://www.monkeycoder.co.nz/Community/posts.php?topic=8127#81432 |
| ||
How about a messaging system, like Windows? Every GUI object is a window with its own ID, which gets passed messages in a standard form via its parent window. Use overrideable functions to implement non-standard functionality. I'm thinking of something like MFC, if you're familiar with it. But maybe you are looking for something more general than a system of windows and controls. |
| ||
I use this heavily in all of my projects: https://github.com/skn3/callbacks It is a fairly simple approach, but it has proven to work nicely on 2 large scale app projects so far. [update] here is an example: Import skn3.callbacks Global CALLBACK_DO_SOMETHING:= RegisterCallbackId("Do Something") Function Main:Int() Local myClass1:= New MyClass("myClass1") Local myClass2:= New MyClass("myClass2") Local myClass3:= New MyClass("myClass3") FireCallback(CALLBACK_DO_SOMETHING, Null, Null) End Class MyClass Implements CallbackReciever Field name:String Method New(name:string) Self.name = name 'add callbacks to this class AddCallbackReciever(Self, CALLBACK_DO_SOMETHING) End Method OnCallback:Bool(id:Int, source:Object, data:Object) Select id Case CALLBACK_DO_SOMETHING Print "CALLBACK_DO_SOMETHING called for " + name End 'return to not block further callbacks Return False End End |
| ||
@Skn3: That's as a Java listener, isn't it? It's functional but what I want to do is to be able to call any arbitrary method on runtime. I mean, at runtime being able to modify the callback. All this could be sort of fixed if we could have a compile-time statically typed GetMethod that, as being resolved at compile time, doesn't require reflection to work. |
| ||
That's how I have actualy implemented my events system (That's a form with 2 buttons and a text field, that performs several actions when buttonsw are pressed, text in the textfield is modified, or the form is resized:Class MyForm Extends Form Field butClose:Button Field butChangeColor:Button Field textField:TextField Method OnInit() butClose = New Button butClose.Parent = Self butClose.Text = "Click me to close this form" 'Add a method to the EventHanler: 'The "ButClose_Clicked" method of "Self" will be automatically invoked when the butClose is clicked. No more code involved. butClose.Event_Click.Add(Self, "ButClose_Clicked") butChangeColor = New Button butChangeColor.Parent = Self butChangeColor.Text = "Click here to change form color" butChangeColor.Position.Y = 40 butChangeColor.Event_Click.Add(Self, "ButChangeColor_Clicked") textField = New TextField textField.Parent = Self textField.Position.Y = 80 textField.AutoAdjustSize = False textField.Size.SetValues(200, 20) textField.Event_TextModified.Add(Self, "TextField_TextModified") Self.Event_Resized.Add(Self, "FormResized") End Method FormResized(sender:Object, e:EventArgs) Self.Text = "New size: " + Self.Size.X + ", " + Self.Size.Y End Method ButClose_Clicked(sender:Object, e:MouseEventArgs) Self.Dispose() End Method ButChangeColor_Clicked(sender:Object, e:MouseEventArgs) Self.TipText = "Back color has been changed." Self.BackgroundColor = New GuiColor(1, Rnd(0, 255), Rnd(0, 255), Rnd(0, 255)) End Method TextField_TextModified(sender:Object, e:EventArgs) Print "Text has been modified on the text field!" End End I do really like how the events system is desiged EXCEPT for this: butChangeColor.Event_Click.Add(Self, "ButChangeColor_Clicked") As it requires reflection to get a sort of "method pointer", this is evaluated at runtime, so coding errors are not detected untill the code is executed. Then, also, it involes reflection, which increases a lot the compilation time. Pros of the system is how dynamic it is. You can attach any method at any time to the Event, as long as it has the appropriated method signature (parameters). Also, more than one method can be associated to each event, and they all will be executed. You can even call a method in any class instance, when an event happens on another class instance. That's a lot like obejct messaging system, I don't think all this can be done with only interfaces, but if anyone has any other idea... ? @Gerry Quinn How about a messaging system, like Windows? I already has this for the "lower level" stuff on the Gui system, so it's faster, etc. but it's not very convenient for higher level coding of a Gui system. It forces big dispatch methods where you select the msg constant and call a given method, etc... that's exactly what I don't want to provide in my gui! |