2008-09-24 11 views
17

Lors de l'écriture d'interfaces utilisateur graphiques, j'ai souvent rencontré le problème suivant: Supposons que vous ayez un modèle et un contrôleur. Le contrôleur a un widget W qui est utilisé pour afficher une propriété X du modèle. Comme le modèle peut être modifié de l'extérieur du contrôleur (il peut y avoir d'autres contrôleurs utilisant le même modèle, opérations d'annulation, etc.), le contrôleur est à l'écoute des modifications apportées au modèle. Le contrôleur écoute également les événements sur le widget W et met à jour la propriété X en conséquence.Cycles d'événements de rupture dans les interfaces graphiques

Maintenant, voilà ce qui se passe:

  1. la valeur W est modifiée
  2. un événement est généré, le gestionnaire dans le contrôleur est invoqué
  3. le contrôleur définit la nouvelle valeur pour X dans le modèle
  4. le m odel émet des événements, car il a été modifié
  5. le contrôleur reçoit un événement de changement du modèle
  6. le contrôleur obtient la valeur de X et fixe dans le widget
  7. goto 1.

Il existe plusieurs solutions possibles pour cela:

  1. Modifier le contrôleur pour définir un indicateur lorsque le modèle est mis à jour et ne pas réagir aux événements du modèle si ce dernier est défini.
  2. Débranchez le contrôleur temporairement (ou dire le modèle de ne pas envoyer aucun événement pour un certain temps)
  3. Gel des mises à jour à partir du widget

Dans le passé, je suis allé plus souvent pour l'option 1., parce qu'il est la chose la plus simple. Il a l'inconvénient d'encombrer vos classes avec des drapeaux, mais les autres méthodes ont aussi leurs inconvénients. Pour l'anecdote, j'ai eu ce problème avec plusieurs toolkits d'interface graphique, y compris GTK +, Qt et SWT, donc je pense que c'est assez agile.

Des meilleures pratiques? Ou l'architecture que j'utilise est-elle simplement incorrecte?

@Shy: C'est une solution dans certains cas, mais vous obtenez toujours une série d'événements superflus si X est modifié de l'extérieur du contrôleur (par exemple, en utilisant le modèle de commande pour annuler/rétablir), car alors la valeur a changé, W est mis à jour et déclenche un événement. Afin d'éviter une autre mise à jour (inutile) du modèle, l'événement généré par le widget doit être avalé.
Dans d'autres cas, le modèle peut être plus complexe et une simple vérification de ce qui a exactement changé peut ne pas être réalisable, par ex. une vue arborescente complexe.

+0

J'ai ce problème avec les zones de liste dans MFC tout le temps. –

Répondre

3

Habituellement, vous devez répondre aux événements d'entrée dans le widget et ne pas modifier les événements. Cela empêche ce type de boucle de se produire.

  1. utilisateur change d'entrée dans le widget
  2. Widget émet l'événement de changement (défilement fait/entrer un congé cliqué/souris, etc.)
  3. répond contrôleur, se traduit par changer dans le modèle
  4. Modèle émet événement
  5. répond contrôleur, la valeur change dans un widget
  6. valeur événement de changement émis, mais pas écouté par le contrôleur
+0

Merci pour la suggestion. Malheureusement, cela n'est pas toujours possible, en fonction de la boîte à outils GUI. –

5

La façon standard de traiter cela et aussi celle suggérée dans leur tutoriel très utile est de faire la modification de la valeur dans le contrôleur seulement si la nouvelle valeur est différente de la valeur actuelle.
Ce sont des signaux de façon ont la sémantique de valueChanged()

see this tutorial

1

drapeaux pour indiquer le travail de updaing. Vous pouvez les inclure dans des méthodes telles que BeginUpdate et EndUpdate.

+0

Est-ce une pratique courante, ou faites-vous simplement une supposition éclairée? – Statement

+0

J'ai utilisé des drapeaux pour indiquer l'état de mise à jour dans le développement de Windows MFC qui avait un document avec l'architecture de vue multiple. Plus récemment, dans le développement Windows .Net, j'ai utilisé des drapeaux pour indiquer si l'événement select change a été déclenché pendant init et pourrait être ignoré. – Leah

Questions connexes