Domanda

Durante la scrittura di GUI, ho riscontrato spesso il seguente problema: supponiamo di avere un modello e un controller. Il controller ha un widget W che viene utilizzato per mostrare una proprietà X del modello.

Poiché il modello potrebbe essere modificato dall'esterno del controller (potrebbero esserci altri controller che utilizzano lo stesso modello, operazioni di annullamento ecc.), il controller ascolta le modifiche sul modello. Il controller ascolta anche gli eventi sul widget W e aggiorna la proprietà X di conseguenza.

Ora, succede quanto segue:

  1. il valore in W è cambiato
  2. viene generato un evento, viene richiamato il gestore nel controller
  3. il controller imposta il nuovo valore per X nel modello
  4. il modello emette eventi perché è stato modificato
  5. il controller riceve un evento di modifica dal modello
  6. il controller ottiene il valore di X e lo imposta nel widget
  7. vai a 1.

Esistono diverse soluzioni possibili per questo:

  1. Modifica il controller per impostare un flag quando il modello viene aggiornato e non reagire agli eventi del modello se questo flag è impostato.
  2. Scollegare temporaneamente il controller (o dire al modello di non inviare eventi per un po 'di tempo)
  3. Blocca eventuali aggiornamenti dal widget

In passato, di solito preferivo l'opzione 1., perché è la cosa più semplice. Ha lo svantaggio di ingombrare le tue classi con le bandiere, ma anche gli altri metodi hanno i loro svantaggi.

Solo per la cronaca, ho avuto questo problema con diversi toolkit GUI, tra cui GTK +, Qt e SWT, quindi penso che sia piuttosto toolkit-agnostico.

Qualche best practice? O l'architettura che uso è semplicemente sbagliata?

@Shy: questa è una soluzione per alcuni casi, ma si ottiene comunque una serie di eventi superflui se X viene modificato dall'esterno del controller (ad esempio, quando si utilizza il modello di comando per annulla / ripristina ), poiché il valore è stato modificato, W viene aggiornato e genera un evento. Per impedire un altro (inutile) aggiornamento del modello, l'evento generato dal widget deve essere ingoiato.
In altri casi, il modello potrebbe essere più complesso e un semplice controllo su ciò che è esattamente cambiato potrebbe non essere fattibile, ad es. una vista ad albero complessa.

È stato utile?

Soluzione

Di solito dovresti rispondere agli eventi di input nel widget e non cambiare eventi. Ciò impedisce che si verifichi questo tipo di loop.

  1. L'utente modifica l'input nel widget
  2. Il widget emette un evento di modifica (scorrimento fatto / inserire clic / lasciare il mouse, ecc.)
  3. Il controller risponde, si traduce in un cambiamento nel modello
  4. L'evento di emissione del modello
  5. Il controller risponde, cambia valore nel widget
  6. Evento di modifica del valore emesso, ma non ascoltato dal controller

Altri suggerimenti

Il modo QT standard di gestire questo e anche quello suggerito nel loro tutorial molto utile è quello di apportare la modifica al valore nel controller solo se il nuovo valore è diverso dal valore corrente.
In questo modo i segnali hanno la semantica di valueChanged()

consulta questo tutorial

Flag per indicare il lavoro di aggiornamento. Puoi avvolgerli in metodi come BeginUpdate ed EndUpdate.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top