tags:

views:

173

answers:

3

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.

+4  A: 

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

shoosh
+1  A: 

Flags to indicate updaing work. You can wrap them in methods like BeginUpdate and EndUpdate.

Leah
Is this a common practice, or are you just making an educated guess?
Statement
I have used flags to indicate updating status in MFC Windows development which had a Document with multiple View architecture. More recently in .Net Windows development I used flags to indicate if the select change event was fired during init and could be ignored.
Leah
+3  A: 

Usually you should respond to input events in the widget and not to change events. This prevents this type of loop from occuring.

  1. User changes input in the widget
  2. Widget emits change event (scroll done / enter clicked / mouse leave, etc.)
  3. Controller responds, translates to change in the model
  4. Model emits event
  5. Controller responds, changes value in widget
  6. Value change event emitted, but not listened to by controller
Redbeard
Thanks for the suggestion. Sadly, this is not always possible, depending on the GUI toolkit.
Torsten Marek