2008-10-06 16 views
3

Je travaille avec une zone de liste déroulante dans une application basée sur Swing, et j'ai du mal à trouver ce qu'il faut faire pour différencier un ItemEvent généré d'un événement utilisateur de celui généré par l'application. Par exemple, Disons que j'ai un combobox, 'combo' et j'écoute des événements itemStateChanged avec mon ItemListener, 'listener'. Lorsque l'utilisateur modifie la sélection au point 2 ou j'exécuter la ligne (pseudo-code):Swing: existe-t-il un moyen de faire la différence entre un ItemEvent généré par l'utilisateur et un ItemEvent causé par l'utilisateur?

combo.setSelection(2)

.. il semble que je ne suis pas en mesure de dire à ces événements en dehors. Cela dit, je ne suis pas un expert de Swing par tous les moyens, alors j'ai pensé que je demanderais.

Merci!

+0

Je ne suis pas ce qui suit. Pourquoi voudriez-vous générer des événements par programme et ensuite vouloir qu'ils soient différents des événements normaux? –

+0

Je ne génère pas d'événements, exactement. J'ai des auditeurs qui "font des choses" qui sont attachés à la combobox. Lorsque l'utilisateur effectue l'action, l'application fonctionne correctement. Cependant, quand j'ai besoin de mettre à jour le combo, il provoque toujours les événements, mais j'en ai besoin traité différemment. – awied

+0

@awied: vous devez également vous préoccuper de la situation dans laquelle une application d'accessibilité utilisateur dirige votre programme. – user7116

Répondre

2

La loi Action et Réaction est assez claire :). Si vous essayez de réagir au changement, il n'est pas nécessaire de faire la distinction entre l'utilisateur et l'application. Je peux imaginer un seul cas d'utilisation où vous devez "distinguer". Le cas où l'application affiche certaines données. Dans ce cas, vous avez probablement un modèle de données pour votre application. Et il y a également un écouteur de modification dans ce modèle et l'interface graphique de l'application réagira en définissant des valeurs sur les composants. Et aussi. Si l'utilisateur sélectionne quoi que ce soit dans le composant de l'interface graphique. Le modèle de données réagira en changeant la valeur. Dans ce cas, il est facile de mettre en place une sorte d'état en lecture seule sur le modèle de données qui avertira le modèle d'ignorer tout événement provenant d'objets observés. Cet ensemble de notifications doit s'exécuter dans EDT et il n'y a aucun problème avec le marquage.Petit exemple:

class ApplicationDataModel { 

    private Flag current = Flag.RW; 

    public void setData(ApplicationData data) { 
     current = Flag.RO; 
     setDataImpl(data); 
     notifyObservers(); 
     current = Flag.RW; 
    } 

    public void reaction(Event e) { 
     if (flag = Flag.RO) return; 
     ... 
    } 

} 

Soyez prudent avec le marquage et ne pas oublier le filetage. Si vous appelez setData à partir d'un autre thread puis EDT vous allez avoir des problèmes. Bien sûr. L'extraction de l'objet ApplicationData doit être exécutée dans un thread différent;). En général, repensez la conception de votre application.

0

Vous pouvez définir un drapeau dans votre code avant de définir la sélection, puis vérifier ce drapeau dans l'auditeur (et unset le drapeau si elle est définie) ...

Il peut y avoir une meilleure façon depuis Java 6, mais c'est la façon dont j'ai toujours l'habitude de le faire ...

[Modifier]: Comme le souligne David, vous devrez définir le drapeau (et mettre à jour le combo) dans l'EDT en utilisant SwingUtilities.invokeLater ou similaire (vous devez le faire quand vous changez un contrôle d'interface utilisateur)

2

Si l'utilisateur sélectionne I tem 2, ou les appels d'API setSelection (2), l'événement apparaîtra le même.

La solution à votre problème pourrait être de repenser ce que vous voulez que le code itemStateChanged fasse quand la sélection change. Pourquoi votre application fonctionne-t-elle différemment dans chaque condition? Peut-être qu'il y a des similitudes que vous pouvez utiliser à votre avantage.

Soyez prudent lorsque vous utilisez les indicateurs. L'événement itemStateChanged se produira sur le thread Dispatch d'événement, qui est un thread différent de celui sur lequel vous définissez l'état de l'indicateur. Cela signifierait que l'utilisation d'un drapeau peut ne pas être fiable à 100%.

0

Si vous avez besoin de distinguer les événements, il y a probablement quelque chose à redire dans votre conception. Le but de MVC est de découpler les modifications du modèle des clics réels de l'utilisateur.

Peut-être vous devriez reformuler la question en termes de pourquoi vous voudriez jamais faire la différence entre ces deux situations. Nous pourrions alors fournir des conseils sur une manière différente d'atteindre l'objectif.

0

Donc je suppose que vous voulez que la sélection de l'utilisateur effectue une action plutôt qu'un simple changement d'état direct. C'est un problème causé par une flexibilité limitée (la flexibilité sera toujours limitée, surtout si vous avez de la flexibilité dans d'autres directions).

Ma suggestion:

Tout d'abord, allez tout droit toujours à l'aide du modèle dans Swing. Les widgets sont trop compliqués et vous voulez séparer les différentes préoccupations. Heureusement, Swing est déjà là avec ses modèles.

Un modèle commun est d'avoir une délégation entre les modèles. Donc, dans ce cas, vous avez le "vrai" modèle par défaut qui contient vos données. Insérer entre le JComboBox et le ComboBoxModel réel et déléguer ComboBoxModel qui effectue des actions sur les instructions de changement d'état. Votre code d'application doit ignorer le JComboBox et aller directement au vrai ComboBoxModel en contournant le modèle de délégation. Donc, dans un diagramme:

 
User -- JComboBox -- ActionComboBoxModel -- DefaultComboBoxModel -- Application code