Swing: Y a-t-il un moyen de différencier un ItemEvent provoqué par l'utilisateur d'un autre provoqué par une application?

StackOverflow https://stackoverflow.com/questions/176150

Question

Je travaille avec une liste déroulante dans une application basée sur Swing et j'ai du mal à savoir quoi faire pour différencier un événementEvent généré à partir d'un événement utilisateur par rapport à un événement provoqué par l'application.

Par exemple, disons que j'ai une liste déroulante ' combo ' et que j'écoute les événements itemStateChanged avec mon ItemListener, ' auditeur '. Lorsqu'un utilisateur modifie la sélection sur l'élément 2 ou que j'exécute la ligne (pseudocode):

combo.setSelection (2)

.. il me semble que je ne suis pas capable de distinguer ces événements.

Cela dit, je ne suis en aucun cas un expert de Swing, alors j’ai pensé pouvoir poser la question.

Merci!

Était-ce utile?

La solution

La loi d'action et de réaction est très claire :). Si vous essayez de réagir au changement, il n'est pas nécessaire de faire la distinction entre utilisateur et application. Je ne peux imaginer qu'un seul cas d'utilisation où vous devez "distinguer". Le cas où l'application affiche des données. Dans ce cas, vous avez probablement un modèle de données pour votre application. De plus, il existe des écouteurs de modification dans ce modèle et l'interface graphique de l'application réagira en définissant des valeurs pour les composants. Et aussi. Si l'utilisateur sélectionne quelque chose dans le composant d'interface graphique. Le modèle de données réagira en modifiant la valeur. Dans ce cas, il est facile de définir 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 l’EDT et il n’ya aucun problème de signalisation. 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;
        ...
    }

}

Faites attention avec le marquage et n'oubliez pas les threads. Si vous appelez setData à partir d'un autre thread, EDT vous avez des problèmes. Bien sûr. L'extraction de l'objet ApplicationData doit être exécutée dans un autre thread;). En général, repensez la conception de votre application.

Autres conseils

Que l'utilisateur sélectionne l'élément 2 ou que l'API appelle setSelection (2), l'événement apparaîtra de la même manière .

La solution à votre problème consiste peut-être à repenser ce que vous voulez que le code itemStateChanged fasse lorsque la sélection change. Pourquoi votre application fonctionnerait-elle différemment dans chaque condition? Il y a peut-être des similitudes que vous pouvez utiliser à votre avantage.

Faites attention lorsque vous utilisez des drapeaux . 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%.

Vous pouvez définir un indicateur dans votre code avant de définir la sélection, puis rechercher cet indicateur dans le programme d'écoute (et désélectionner l'indicateur s'il est défini) ...

Il existe peut-être une meilleure solution depuis Java 6, mais c’est ce que j’ai toujours fait.

[Modifier] : comme le souligne David, vous devez définir l'indicateur (et mettre à jour le combo) dans l'EDT à l'aide de SwingUtilities.invokeLater ou similaire (vous devez le faire de toute changez un contrôle d'interface utilisateur)

Si vous devez différencier les événements, votre conception doit probablement être repensée. L’intérêt principal de MVC est de découpler les modifications apportées au modèle des clics de souris de l’utilisateur.

Peut-être devriez-vous reformuler la question en termes de pourquoi vous voudriez un jour différencier ces deux situations. Nous pourrions alors donner des indications sur une autre manière d'atteindre l'objectif.

Je suppose donc que vous voulez que la sélection de l'utilisateur exécute 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, en particulier si vous avez la flexibilité dans d'autres directions).

Ma suggestion:

Tout d’abord, utilisez toujours directement le modèle dans Swing. Les widgets sont compliqués et vous souhaitez séparer différentes préoccupations. Heureusement, Swing existe déjà avec ses modèles.

Un modèle courant consiste à avoir une délégation entre les modèles. Donc, dans ce cas, vous avez le " réel " modèle par défaut qui contient vos données. Insertion entre JComboBox et réel ComboBoxModel et délégation de ComboBoxModel qui effectue des actions sur les instructions de changement d'état. Votre code d'application doit ignorer le JComboBox et aller directement au véritable ComboBoxModel en ignorant le modèle qui délègue. Donc, dans un diagramme:

User -- JComboBox -- ActionComboBoxModel -- DefaultComboBoxModel -- Application code
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top