Saturday, June 11, 2005

Mindwrapper event handlers

Prism and Mindwrapper are so intimately related that I could easily write about them both in the same place, but I want to reserve the Prism blog for thoughts about clinical application(s) and related issues. Therefore I've created a separate blog here to discuss issues of a more technical nature.

This posting started out to be just a test to make sure I have set things up correctly, but since I have an active issue on my mind right now, I'll write a little about it now.

The Mindwrapper syntax is essentially declarative in nature. Although it is possible to include procedural style Python code in the assemble() definitions, I have tried to discourage this practice (by making it mostly unnecessary). The user-developer will surely want to put procedural code someplace, though, so the trick is to keep it in well-designated locations. Since procedural code is executed in response to an event, such code may be considered an event handler. In the abstraction layer, this code is found primarily in the forward() (and possibly backward()) method(s) of dependent cells. [Note: when I have time, go back and review what mw.Map.update() does.] The forward() method acts as an event handler, where each event is a change in one of the observables to which the dependent cell is attached. In the abstraction layer there is just one type of event to be handled (the change event). Thus binding the handler to the event source is straightforward (and entirely transparent to the user-developer).

In the presentation layer, however, there are many different kinds of events. For some presenters, such as mw.Field, the expected events (EVT_CHAR and EVT_KILL_FOCUS) are handled the same way in every instance. In these cases, binding events to their handlers is automatic and transparent. On the other hand, some presenters, such as mw.Button, are designed to have custom commands associated with them. This might be called the controller role of a presenter. The user-developer must write the procedural code in a method and bind this code to the proper event (EVT_BUTTON). The question is where is the best place to define this method (the event handler)?

One option would be to define a subclass of mw.Button overriding the on_command() method. Access to outside entities would have to be through a "global" attribute self.frame or self.app. A second option would be to define a named handler in the composite presenter where the button is added and use the "command = " parameter of the add() method. A third option would be to define the handler upstream, say in the enclosing frame, and again use the "command = " parameter.

A fourth option has occurred to me, which is to define a separate class for the command itself, say with a do() method. The class would be passed to the "command = " parameter of the add() method and mw.Button would know to bind the EVT_BUTTON event to the do() method of the instance. Potentially there are two advantages of such an implementation. One is that the command could be given an undo() method as well. And the other is that the command could be used by other presenters, such as a menu item (not that a custom handler would not also be available to both button and menu item). At any rate, I have not implemented this last option, but it might warrant experimentation.

0 Comments:

Post a Comment

<< Home