Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Breaking event cycles in GUIs

When writing GUIs, I've frequently come over the following problem: Assume you have a model and a controller. The controller has a widget W that is used to show a property X of the model.

Because the model might be changed from outside the controller (there might be other controllers using the same model, undo operations etc), the controller listens to changes on the model. The controller also listens to events on the widget W and updates the property X accordingly.

Now, the following happens:

  1. the value in W is changed
  2. an event is generated, the handler in the controller is invoked
  3. the controller sets the new value for X in the model
  4. the model emits events because it has been changed
  5. the controller receives a change event from the model
  6. the controller gets the value of X and sets it in the widget
  7. goto 1.

There are several possible solutions for that:

  1. Modify the controller to set a flag when the model is updated, and not react to any events from the model if this flag is set.
  2. Disconnect the controller temporarily (or tell the model not to send any events for some time)
  3. Freeze any updates from the widget

In the past, I usually went for option 1., because it's the simplest thing. It has the drawback of cluttering your classes with flags, but the other methods have their drawbacks, too.

Just for the record, I've had this problem with several GUI toolkits, including GTK+, Qt and SWT, so I think it's pretty toolkit-agnostic.

Any best practices? Or is the architecture I use simply wrong?

@Shy: That's a solution for some cases, but you still get a round of superfluous events if X is changed from outside the controller (for instance, when using the command pattern for undo/redo), because then the value has changed, W is updated and fires an event. In order to prevent another (useless) update to the model, the event generated by the widget has to be swallowed.
In other cases, the model might be more complex and a simple check on what exactly has changed might not be feasible, e.g. a complex tree view.

like image 669
Torsten Marek Avatar asked Sep 24 '08 00:09

Torsten Marek


1 Answers

The standard QT way of dealing with this and also the one suggested in their very useful tutorial is to make the change to the value in the controller only if the new value is different from the current value.
This is way signals have the semantics of valueChanged()

see this tutorial

like image 101
shoosh Avatar answered Sep 30 '22 21:09

shoosh