2009-08-11 6 views
11

Je pourrais vraiment utiliser une case à cocher tri-déclarée en Java. Cela ressemble à une chose simple, mais j'ai seulement vu vraiment ugly implementations [note: lien maintenant cassé]. Trois boutons radio prennent trop de l'immobilier et seront probablement déroutant pour les utilisateurs dans mon cas. C'est essentiellement pour une boîte de dialogue de recherche. J'ai besoin d'options vraies, fausses ou "ne m'en soucie pas". Y a-t-il une technique différente que les gens utilisent?Cases à cocher Tristate en Java

Répondre

5

J'ai trouvé un moyen de faire une case à cocher trois états en ajoutant simplement un auditeur:


public class TriStateActionListener implements ActionListener{ 
    final protected Icon icon; 

    public TriStateActionListener(Icon icon){ 
     this.icon=icon; 
    } 

    public static Boolean getState(javax.swing.JCheckBox cb){ 
     if (cb.getIcon()==null) return null; 
     if (cb.isSelected()) return true; 
     else return false; 
    } 

    public void actionPerformed(ActionEvent e) { 
     javax.swing.JCheckBox cb=(javax.swing.JCheckBox)e.getSource(); 
     if (!cb.isSelected()){ 
      cb.setIcon(icon); 
     } 
     else if (cb.getIcon()!=null){ 
      cb.setIcon(null); 
      cb.setSelected(false); 
     } 
    } 
} 

Ensuite, dans le code de l'application, il est juste une seule ligne:


jCheckBox1.addActionListener(new TriStateActionListener(getResourceMap().getIcon("TriStateIcon"))); 

Après tout commentaires, je pense qu'un menu déroulant pourrait être un meilleur choix. Mais, je voulais partager mon code ici pour tout le monde.

14

Utilisez une liste déroulante.

+1

+1 bonne idée. Si un composant d'interface utilisateur est difficile à coder et non standard, il le sera également pour l'utilisateur. À quand remonte la dernière fois que vous avez utilisé une case à cocher à trois états? Je n'ai jamais. –

+8

Bien que je sois d'accord avec le point de @ byron, une case à cocher à trois états est en fait assez standard du point de vue des utilisateurs. –

+5

Quels utilisateurs? Je suis un développeur et un utilisateur expérimenté, et je méprise les cases à cocher à trois états, généralement parce que le sens du troisième état n'est pas clair; généralement, cela signifie que certains détails vous sont cachés. C'est un cauchemar d'accessibilité et d'accessibilité. – Rob

0

Je voudrais juste utiliser celui que vous avez posté.

Tant que votre complexité est dans une autre classe (ça marche) et qu'elle agit comme n'importe quel autre contrôle, qui s'en soucie? (Cela semble être l'hypothèse derrière tout swing, la plupart des classes swing semblent être à ce sujet compliqué.)

2

Cette "implémentations moche" est un ancien lien. Une des suggestions sur cette page a été mise à jour il y a quelques années. Je n'ai pas testé l'ancienne implémentation, donc je ne sais pas si le nouveau est meilleur ou pire.

TristateCheckBox Revisited

+0

Oui, je pense que Heinz Kabutz, l'a très bien fait. Je recommanderais aussi cela! – codevour

0

Modifier l'interface utilisateur. Tristate check-box est inhabituel et peut vraiment dérouter les utilisateurs. Le menu déroulant est une bonne option, mais pour plus d'une occurrence dans le dialogue, cela apportera aussi beaucoup de confusion à l'utilisateur.

2

Les cases à cocher Tristate sont des idiomes d'interface utilisateur standard pour Treeviews avec des nœuds enfants partiellement vérifiés. Ils sont largement utilisés dans la gestion des couches dans des vues hiérarchiques complexes telles que Google Earth.

3

JIDE ont ouvert le code source des fonctionnalités très agréable dans leur Common Layer, l'un qui se trouve être une case à cocher trois états

Tristate checkboxes

Je suggère que vous allez exécuter le webstart demo pour voir si elle répond à vos besoins

4

enter image description here

Dans cette mise en œuvre des trois états peut être uniquement réglé par programmation. Pour être portable, il utilise des images qui doivent être placées dans le même paquet java.

enter image description here enter image description here enter image description here

public class TristateCheckBox extends JCheckBox { 

    private static final long serialVersionUID = 1L; 
    private boolean halfState; 
    private static Icon selected = new javax.swing.ImageIcon(TristateCheckBox.class.getResource("selected.png")); 
    private static Icon unselected = new javax.swing.ImageIcon(TristateCheckBox.class.getResource("unselected.png")); 
    private static Icon halfselected = new javax.swing.ImageIcon(TristateCheckBox.class.getResource("halfselected.png")); 

    @Override 
    public void paint(Graphics g) { 
     if (isSelected()) { 
      halfState = false; 
     } 
     setIcon(halfState ? halfselected : isSelected() ? selected : unselected); 
     super.paint(g); 
    } 

    public boolean isHalfSelected() { 
     return halfState; 
    } 

    public void setHalfSelected(boolean halfState) { 
     this.halfState = halfState; 
     if (halfState) { 
      setSelected(false); 
      repaint(); 
     } 
    } 
} 

cadre de l'échantillon:

public class NewJFrame19 extends javax.swing.JFrame { 

    private final TristateCheckBox myCheckBox; 

    public NewJFrame19() { 
     myCheckBox = new TristateCheckBox(); 
     myCheckBox.setText("123123"); 
     add(myCheckBox); 

     jButton1 = new javax.swing.JButton(); 

     setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 
     getContentPane().setLayout(new java.awt.FlowLayout()); 

     jButton1.setText("jButton1"); 
     jButton1.addActionListener(new java.awt.event.ActionListener() { 
      public void actionPerformed(java.awt.event.ActionEvent evt) { 
       jButton1ActionPerformed(evt); 
      } 
     }); 
     getContentPane().add(jButton1); 

     pack(); 
    } 

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {           
     myCheckBox.setHalfSelected(true); 
    }           

    public static void main(String args[]) { 

     try { 
      for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { 
       if ("Windows".equals(info.getName())) { 
        javax.swing.UIManager.setLookAndFeel(info.getClassName()); 
        break; 
       } 
      } 
     } catch (ClassNotFoundException ex) { 
      java.util.logging.Logger.getLogger(NewJFrame19.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 
     } catch (InstantiationException ex) { 
      java.util.logging.Logger.getLogger(NewJFrame19.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 
     } catch (IllegalAccessException ex) { 
      java.util.logging.Logger.getLogger(NewJFrame19.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 
     } catch (javax.swing.UnsupportedLookAndFeelException ex) { 
      java.util.logging.Logger.getLogger(NewJFrame19.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 
     } 
     /* Create and display the form */ 
     java.awt.EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       new NewJFrame19().setVisible(true); 
      } 
     }); 
    } 
    private javax.swing.JButton jButton1; 
} 
+1

Nous avons utilisé cette approche pour une case à cocher indiquant l'agrégation des états marche/arrêt. L'interaction active/désactive tout, l'état intermédiaire n'est accessible que via l'interaction avec les éléments individuels. Fonctionne très bien et je pense que c'est plus sain en termes de conception de l'interface utilisateur. –

3

Je ne sais pas pourquoi quelqu'un voudrait donner les solutions avec les fichiers d'icônes supplémentaires alors que java api donne une grande fonctionalité pour override méthode paintIcon (..).

La meilleure solution légère à retenir de l'état CheckBox est l'attribut IMO ClientProperty.

enter image description here

/* 
* Tri-state checkbox example 
* @s1w_ 
*/ 
import javax.swing.*; 
import java.awt.*; 
import java.awt.event.*; 


class TCheckBox extends JCheckBox implements Icon, ActionListener { 

    final static boolean MIDasSELECTED = true; //consider mid-state as selected ? 


    public TCheckBox() { this(""); } 

    public TCheckBox(String text) { 
     super(text); 
     putClientProperty("SelectionState", 0); 
     setIcon(this); 
     addActionListener(this); 
    } 

    public TCheckBox(String text, int sel) { 
     /* tri-state checkbox has 3 selection states: 
     * 0 unselected 
     * 1 mid-state selection 
     * 2 fully selected 
     */ 
     super(text, sel > 1 ? true : false); 

     switch (sel) { 
      case 2: setSelected(true); 
      case 1: 
      case 0: 
       putClientProperty("SelectionState", sel); 
       break; 
      default: 
       throw new IllegalArgumentException(); 
     } 
     addActionListener(this); 
     setIcon(this); 
    } 

    @Override 
    public boolean isSelected() { 
     if (MIDasSELECTED && (getSelectionState() > 0)) return true; 
     else return super.isSelected(); 
    } 

    public int getSelectionState() { 
     return (getClientProperty("SelectionState") != null ? (int)getClientProperty("SelectionState") : 
             super.isSelected() ? 2 : 
             0); 
    } 

    public void setSelectionState(int sel) { 
     switch (sel) { 
      case 2: setSelected(true); 
        break; 
      case 1: 
      case 0: setSelected(false); 
        break; 
      default: throw new IllegalArgumentException(); 
     } 
     putClientProperty("SelectionState", sel); 
    } 


    final static Icon icon = UIManager.getIcon("CheckBox.icon"); 

    @Override 
    public void paintIcon(Component c, Graphics g, int x, int y) { 
     icon.paintIcon(c, g, x, y); 
     if (getSelectionState() != 1) return; 

     int w = getIconWidth(); 
     int h = getIconHeight(); 
     g.setColor(c.isEnabled() ? new Color(51, 51, 51) : new Color(122, 138, 153)); 
     g.fillRect(x+4, y+4, w-8, h-8); 

     if (!c.isEnabled()) return; 
     g.setColor(new Color(81, 81, 81)); 
     g.drawRect(x+4, y+4, w-9, h-9); 
    } 

    @Override 
    public int getIconWidth() { 
     return icon.getIconWidth(); 
    } 

    @Override 
    public int getIconHeight() { 
     return icon.getIconHeight(); 
    } 

    public void actionPerformed(ActionEvent e) { 
     TCheckBox tcb = (TCheckBox)e.getSource(); 
     if (tcb.getSelectionState() == 0) 
      tcb.setSelected(false); 

     tcb.putClientProperty("SelectionState", tcb.getSelectionState() == 2 ? 0 : 
                tcb.getSelectionState() + 1); 

     // test 
     System.out.println(">>>>IS SELECTED: "+tcb.isSelected()); 
     System.out.println(">>>>IN MID STATE: "+(tcb.getSelectionState()==1)); 
    } 
} 
utilisation

: TCheckBox tcb = new TCheckBox("My CheckBox");

Questions connexes