Beim Schreiben von GUIs habe ich häufig das folgende Problem kommen: Angenommen, Sie haben ein Modell und einen Controller. Der Controller verfügt über ein Widget W
, das verwendet wird, um eine Eigenschaft X
des Modells anzuzeigen.Breaking Event Cycles in GUIs
Da das Modell möglicherweise von außerhalb des Controllers geändert wird (möglicherweise gibt es andere Controller, die dasselbe Modell verwenden, Operationen rückgängig machen usw.), hört der Controller Änderungen am Modell ab. Der Controller überwacht auch Ereignisse auf dem Widget W
und aktualisiert die Eigenschaft X
entsprechend.
Nun geschieht Folgendes:
- der Wert in
W
geändert wird - ein Ereignis erzeugt wird, der Handler in der Controller
- die Controller aufgerufen wird den neuen Wert legt für
X
in der Modell - die m odel emittiert Ereignisse, weil es
- die Controller empfängt ein Änderungsereignis vom Modell
- der Controller wird der Wert von
X
und setzt sie in das Widget - goto 1. geändert wurde
Es gibt mehrere mögliche Lösungen dafür:
- Ändern Sie den Controller, um beim Aktualisieren des Modells ein Flag zu setzen, und reagieren Sie nicht auf Ereignisse vom Modell, wenn dieses Flag gesetzt ist.
- Trennen Sie den Controller vorübergehend (oder das Modell sagen, keine Ereignisse für einige Zeit zu senden)
- Frieren keine Updates aus dem Widget
In der Vergangenheit ging ich in der Regel für die Option 1, weil es die einfachste Sache. Es hat den Nachteil, dass Sie Ihre Klassen mit Flaggen überfluten, aber die anderen Methoden haben auch ihre Nachteile.
Nur für das Protokoll, ich hatte dieses Problem mit mehreren GUI Toolkits, einschließlich GTK +, Qt und SWT, also ich denke, es ist ziemlich toolkit-agnostic.
Best Practices? Oder ist die Architektur, die ich verwende, einfach falsch?
@Shy: Das ist eine Lösung für einige Fälle, aber Sie erhalten immer noch eine Runde überflüssiger Ereignisse, wenn X
von außerhalb des Controllers geändert wird (z. B. bei Verwendung des Befehlsmusters für Rückgängig/Wiederholen), weil dann der Wert hat sich geändert, W
wird aktualisiert und löst ein Ereignis aus. Um eine weitere (nutzlose) Aktualisierung des Modells zu verhindern, muss das vom Widget erzeugte Ereignis verschluckt werden.
In anderen Fällen könnte das Modell komplexer sein und eine einfache Überprüfung dessen, was sich genau geändert hat, könnte nicht durchführbar sein, z. eine komplexe Baumansicht.
Ich habe dieses Problem mit Listenfeldern in MFC die ganze Zeit. –