2009-08-13 7 views
4

OK, donc si j'ajouter un ActionListener à un élément graphique, et il est le seul élément j'utilise ce ActionListener avec, est-il important que des lignes suivantes (a, b) I utiliser pour obtenir l'état sélectionné checkbox?auditeurs d'action et les sources d'événements Swing

final JCheckBox checkbox = (JCheckBox)this.buildResult.get("cbDebugTick"); 
checkbox.addActionListener(new ActionListener() { 
    @Override public void actionPerformed(ActionEvent event){    
      boolean bChecked = 
      // (a) checkbox.isSelected(); 
      // (b) ((JCheckBox)event.getSource()).isSelected(); 
      model.setPrintDebugOn(bChecked); 
     } 
}); 

Il me semble logique que si j'ajoute l'objet ActionListener à plusieurs éléments de l'interface graphique, alors je devrais utiliser (b).

Et (b), est-il correct de aveuglément jeté event.getSource()-JCheckBox, depuis que je suis celui qui a ajouté l'auditeur d'action, ou devrais-je faire défensivement et programmer une vérification instanceof?

note: cette question est dans le contexte des écouteurs d'événements en général; kdgregory a quelques bons points ci-dessous spécifiquement re: cases à cocher que j'avais négligé de considérer.

Répondre

0

dans (b) pour être rigoureux, vous devrait en effet faire une instance de vérification, mais ce n'est pas si important. Je pense que ces deux lignes sont correctes et acceptables, bien que (b) serait "meilleur code"

Bien que, ce qui est habituellement fait dans un écouteur d'action est simplement d'appeler une autre méthode personnalisée à votre case à cocher. Donc, il ressemblerait à quelque chose comme ceci:

@Override public void actionPerformed(ActionEvent event) {         
    //your treatment would be in this method, where it would be acceptable to use (a)     
    onCheckBoxActionPerformed(event) 
} 
+0

pourriez-vous élaborer? pourquoi rediriger vers la classe externe si vous pouvez avoir accès aux mêmes méthodes/champs dans une classe interne anonyme? –

+0

de cette façon vous pouvez facilement ajouter différents composants au même écouteur d'action et les traiter différemment et/ou polymorphiquement, rendant le code "meilleur" –

+1

Je ne suis pas d'accord avec l'affirmation de David. Transférer un appel comme celui-ci va à l'encontre du découplage (c'est pourquoi une approche d'auditeur a été adoptée pour la notification d'événement dans Swing en premier lieu). Le cas idéal est celui où vous pouvez entièrement décomposer le comportement de l'action et utiliser l'action listener external à la vue qui contient le contrôle - dans ce cas, l'option (b) est la technique préférée. Cela dit, ce que vous * devriez * faire est de créer une Action et d'y attacher le contrôle. –

0

Je programmerais avec b défensivement car c'est l'option de la meilleure pratique. Mais si seulement vous allez utiliser le code, alors il n'y a aucune raison pour laquelle vous ne pouvez pas faire un. Cependant, imaginez combien vous serez heureux avec vous si vous y revenez plus tard, changez quelque chose et trouvez que vous avez écrit un bon code que vous pouvez directement réutiliser ...

3

Je ne ferais ni l'un ni l'autre.

Si vous cliquez sur la case à cocher pour commencer une action, j'attacher un ItemListener, puis regardez simplement l'état de la sélection dans le ItemEvent. Cependant, les cases à cocher n'appellent normalement pas d'actions, elles gèrent l'état. Donc, une meilleure approche consiste à examiner toutes vos cases à cocher en réponse à tout ce qui déclenche l'action.


Éditer: quelques commentaires sur les problèmes plus importants soulevés par l'OP. Tout d'abord, il est important de réaliser que de grandes parties de Swing représentent la commodité d'implémentation plutôt qu'un modèle de comportement cohérent. JCheckBox et JButton n'ont rien de commun si ce n'est que le fait de cliquer dans leur espace est significatif. Cependant, ils héritent tous deux de AbstractButton, qui fournit des détails d'implémentation tels que l'étiquette du bouton. Il suppose également que les boutons sont "pressés", et qu'appuyer sur un bouton initiera un comportement significatif (l'action). Dans le cas de JCheckbox, cependant, la pression du bouton n'est pas importante, le changement d'état est. Ce changement d'état est signalé à ItemListener - qui est également défini sur AbstractButton même si les changements d'état n'ont aucun sens pour les autres types de boutons (le JavaDoc indique même "checkbox"). L'une des choses que Swing a réussi à faire - si difficile à utiliser - est l'idée qu'un Action est séparé du contrôle qui lance cette action. Un objet Action peut être appelé à partir de plusieurs contrôles: un élément de menu, un bouton de commande dans une boîte de dialogue, une séquence de touches, etc.Plus important du point de vue de la conception, cela vous éloigne de l'idée d'un «auditeur» générique qui essaie de comprendre ce qui doit se passer. J'ai vu des applications où un seul écouteur reçoit une entrée de l'ensemble du système de menus, par exemple, puis passe par une grande chaîne if/else pour déterminer quel élément de menu a été pressé. Utiliser les actions signifie que vous avez plus de classes, mais à long terme vous donne une application plus maintenable. Enfin, d'un point de vue de la convivialité, il existe une différence entre les contrôles qui conservent l'état, tels que JCheckbox et JTextArea, et ceux qui déclenchent des actions, tels que JButton et JMenuItem. J'ai vu une application (web) où cliquer sur un bouton radio vous amène à une page différente. C'est mauvais. Même si vous prévoyez d'utiliser les écouteurs en interne, pour mettre à jour l'état de certains modèles, vous devriez vous demander pourquoi la collection d'éléments de l'interface graphique ne vous fournit pas de modèle.

+0

un point valide ... mais ce n'était pas ma question –

+0

C'est vrai, mais il y aura peut-être une autre personne qui trouvera cette question via Google, et préférera utiliser l'API de manière appropriée, plutôt que de s'inquiéter de savoir lequel des deux hacks est " meilleur." – kdgregory

+0

c'est juste, je vais le noter dans la question. +1 pour l'autre commentaire à la fin: dans ce cas j'utilisais l'écouteur pour propager l'état de case à cocher à un objet modèle qui ne connaissait pas la case à cocher, je suppose que je devrais utiliser javax.swing.JToggleButton.ToggleButtonModel au lieu de un écouteur d'événement. –

1

Pour le cas où l'écouteur est exclusif (comme un écouteur anon), j'utilise (a).

Si l'auditeur sera réutilisée (par exemple, this est une instance de ActionListener) Je vais écrire comme:

@Override 
public void actionPerformed(ActionEvent event) { 
    Object src = event.getSource(); 
    if (src == checkbox) { 
     boolean bChecked = checkbox.isSelected(); 
     // ... 
    } 
} 

Si vous avez plusieurs cases à cocher et ils sont traités de la même façon, puis instanceof a du sens.

Questions connexes