web-dev-qa-db-fra.com

Exécuter une action lorsqu'un élément de la liste déroulante est sélectionné

J'ai un jcombobox contenant item1 et item2, j'ai aussi un jtextfield .. quand je sélectionne item1 sur mon jcombobox, je veux que 30 apparaisse sur mon jtextfield alors que 40 si Item2 a été sélectionné ... Comment puis-je le faire?

3
mitche027

voici comment vous le faites avec ActionLIstener

import Java.awt.FlowLayout;
import Java.awt.event.*;

import javax.swing.*;

public class MyWind extends JFrame{

    public MyWind() {
        initialize();
    }

    private void initialize() {
        setSize(300, 300);
        setLayout(new FlowLayout(FlowLayout.LEFT));
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        final JTextField field = new JTextField();
        field.setSize(200, 50);
        field.setText("              ");

        JComboBox comboBox = new JComboBox();
        comboBox.setEditable(true);
        comboBox.addItem("item1");
        comboBox.addItem("item2");

        //
        // Create an ActionListener for the JComboBox component.
        //
        comboBox.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                //
                // Get the source of the component, which is our combo
                // box.
                //
                JComboBox comboBox = (JComboBox) event.getSource();

                Object selected = comboBox.getSelectedItem();
                if(selected.toString().equals("item1"))
                field.setText("30");
                else if(selected.toString().equals("item2"))
                    field.setText("40");

            }
        });
        getContentPane().add(comboBox);
        getContentPane().add(field);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new MyWind().setVisible(true);
            }
        });
    }
}
11
secario

La solution simple serait d'utiliser un ItemListener. Lorsque l'état change, il vous suffit de vérifier l'élément actuellement sélectionné et de définir le texte en conséquence

import Java.awt.BorderLayout;
import Java.awt.EventQueue;
import Java.awt.event.ItemEvent;
import Java.awt.event.ItemListener;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestComboBox06 {

    public static void main(String[] args) {
        new TestComboBox06();
    }

    public TestComboBox06() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public class TestPane extends JPanel {

        private JComboBox cb;
        private JTextField field;

        public TestPane() {
            cb = new JComboBox(new String[]{"Item 1", "Item 2"});
            field = new JTextField(12);

            add(cb);
            add(field);

            cb.setSelectedItem(null);

            cb.addItemListener(new ItemListener() {
                @Override
                public void itemStateChanged(ItemEvent e) {
                    Object item = cb.getSelectedItem();
                    if ("Item 1".equals(item)) {
                        field.setText("20");
                    } else if ("Item 2".equals(item)) {
                        field.setText("30");
                    }
                }
            });
        }

    }

}

Une meilleure solution serait de créer un objet personnalisé qui représente la valeur à afficher et la valeur qui lui est associée ...

Mis à jour

Maintenant que je n'ai plus 10 mois à mâcher sur mes chevilles, j'ai mis à jour l'exemple pour utiliser une variable ListCellRenderer qui est une approche plus correcte que paresseuse en remplaçant la variable toString

import Java.awt.BorderLayout;
import Java.awt.Component;
import Java.awt.EventQueue;
import Java.awt.event.ItemEvent;
import Java.awt.event.ItemListener;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestComboBox06 {

    public static void main(String[] args) {
        new TestComboBox06();
    }

    public TestComboBox06() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public class TestPane extends JPanel {

        private JComboBox cb;
        private JTextField field;

        public TestPane() {
            cb = new JComboBox(new Item[]{
                new Item("Item 1", "20"), 
                new Item("Item 2", "30")});
            cb.setRenderer(new ItemCelLRenderer());
            field = new JTextField(12);

            add(cb);
            add(field);

            cb.setSelectedItem(null);

            cb.addItemListener(new ItemListener() {
                @Override
                public void itemStateChanged(ItemEvent e) {
                    Item item = (Item)cb.getSelectedItem();
                    field.setText(item.getValue());
                }
            });
        }

    }

    public class Item {
        private String value;
        private String text;

        public Item(String text, String value) {
            this.text = text;
            this.value = value;
        }

        public String getText() {
            return text;
        }

        public String getValue() {
            return value;
        }

    }

    public class ItemCelLRenderer extends DefaultListCellRenderer {

        @Override
        public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); //To change body of generated methods, choose Tools | Templates.
            if (value instanceof Item) {
                setText(((Item)value).getText());
            }
            return this;
        }

    }

}
2
MadProgrammer

Pas une réponse à la question initiale, mais un exemple pour les rendus personnalisés réutilisables et fonctionnels sans casser MVC :-)

// WRONG
public class DataWrapper {
   final Data data;
   final String description;
   public DataWrapper(Object data, String description) {
       this.data = data;
       this.description = description;
   }
   ....
   @Override
   public String toString() {
       return description;
   } 
}
// usage
myModel.add(new DataWrapper(data1, data1.getName());

C'est faux dans un environnement MVC, car il mélange les données et la vue: maintenant, le modèle ne contient pas le données, mais un wrapper introduit pour vue. _ les raisons. Cela brise la séparation des problèmes et l'encapsulation (chaque classe qui interagit avec le modèle doit être consciente des données encapsulées).

Les éléments moteurs de la violation des règles étaient:

  • conserve la fonctionnalité du KeySelectionManager par défaut (qui est cassé par un moteur de rendu personnalisé)
  • réutilisation de la classe wrapper (peut être appliqué à tout type de données)

Comme dans Swing, un moteur de rendu personnalisé est le petite pièce conçue pour permettre une représentation visuelle personnalisée, un gestionnaire par défaut qui ne peut pas s'en sortir est ... cassé. Modifier le design juste pour s'adapter à un défaut aussi merdique est à l'envers, un peu à l'envers. Le bon est de mettre en place un gestionnaire d’adaptation.

Bien que la réutilisation soit une bonne chose, le faire au prix de casser l’architecture de base n’est pas une bonne affaire.

Nous avons un problème dans le domaine de la présentation, résolvons-le avec les éléments conçus pour résoudre exactement ce problème. Comme vous l'avez peut-être deviné, SwingX a déjà une telle solution :-)

Dans SwingX, le fournisseur d'une représentation sous forme de chaîne s'appelle StringValue, et tous les rendus par défaut utilisent une telle StringValue pour se configurer eux-mêmes:

StringValue sv = new StringValue() {
     @Override
     public String getString(Object value) {
        if (value instanceof Data) {
            return ((Data) value).getSomeProperty();
        }
        return TO_STRING.getString(value);
     }
};
DefaultListRenderer renderer = new DefaultListRenderer(sv);

Comme defaultRenderer est une StringValue (implémentée pour déléguer à une donnée), une implémentation bien conçue de KeySelectionManager peut désormais déléguer à la fonctionnalité de rendu la recherche de l'élément approprié:

public BetterKeySelectionManager implements KeySelectionManager {

     @Override
     public int selectionForKey(char ch, ComboBoxModel model) {

         ....
         if (getCellRenderer() instance of StringValue) {
              String text = ((StringValue) getCellRenderer()).getString(model.getElementAt(row));
              ....
         } 
     }

}

Décrit l'approche parce qu'elle est facilement implémentable même sans utiliser SwingX, il suffit de définir implémenter quelque chose de similaire et de l'utiliser:

  • un fournisseur d'une représentation de chaîne
  • un moteur de rendu personnalisé, configurable par ce fournisseur et garantissant son utilisation lors de sa configuration
  • un keySelectionManager bien comporté avec des requêtes du moteur de rendu pour sa représentation de chaîne

Tout, sauf le fournisseur de chaîne, est réutilisable tel quel (c'est exactement une implémentation du rendu personnalisé et du gestionnaire keySelectionManager). Il peut y avoir des implémentations générales du fournisseur de chaîne, f.i. les valeurs de formatage ou l’utilisation des propriétés du haricot par réflexion Et tout cela sans enfreindre les règles de base :-)

1
kleopatra