web-dev-qa-db-ja.com

コンボボックスのアイテムが選択されたときにアクションを実行します

Item1とitem2を含むjcomboboxがあり、jtextfieldもあります。jcomboboxでitem1を選択すると、jtextfieldに30が表示され、Item2が選択されている場合は40が表示されます。どうすればよいですか?

4
mitche027

これは、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

単純な解決策は、ItemListenerを使用することです。状態が変化したときは、現在選択されているアイテムを確認し、それに応じてテキストを設定するだけです

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");
                    }
                }
            });
        }

    }

}

より良い解決策は、表示される値とそれに関連付けられた値を表すカスタムオブジェクトを作成することです...

更新済み

10か月足首を噛んでいなくなったので、ListCellRendererを使用するように例を更新しました。これは、より正確なアプローチであり、怠惰で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

元の質問への回答ではなく、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());

データとビューが混在しているため、MVC環境ではwrongです。モデルにはデータが含まれていませんしかしviewの理由で導入されたラッパー。これは、懸念事項とカプセル化の分離を壊しています(モデルと対話するすべてのクラスは、ラップされたデータを認識する必要があります)。

ルール違反の原動力は次のとおりです。

  • デフォルトのKeySelectionManagerの機能を維持します(これはカスタムレンダラーによって破壊されます)
  • ラッパークラスの再利用(任意のデータ型に適用可能)

Swingの場合、カスタムレンダラーはtheカスタムビジュアル表現に対応するように設計された小さなコインなので、対応できないデフォルトのマネージャーは...壊れています。そのようなくだらないデフォルトに対応するためだけにデザインを微調整することは、逆の方法で、間違った方法です。正しいのは、対処マネージャを実装することです。

再利用は問題ありませんが、基本的なアーキテクチャを壊すという犠牲を払ってそうすることは、適切なバージンではありません。

プレゼンテーション領域に問題があります。その問題を正確に解決するように設計された要素を使用して、プレゼンテーション領域で解決しましょう。ご想像のとおり、 SwingX にはすでにそのような解決策があります:-)

SwingXでは、文字列表現のプロバイダーはStringValueと呼ばれ、すべてのデフォルトレンダラーはそのようなStringValueを使用して自分自身を構成します。

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);

DefaultRendererはStringValue(指定されたオブジェクトに委譲するために実装されている)であるため、正常に動作するKeySelectionManagerの実装は、レンダラーに委任して適切なアイテムを見つけることができます。

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));
              ....
         } 
     }

}

SwingXを使用しなくても簡単に実装できるため、アプローチの概要を説明しました。同様の実装を定義して使用するだけです。

  • 文字列表現のプロバイダ
  • そのプロバイダーによって構成可能であり、それ自体の構成でそれを使用することを保証するカスタムレンダラー
  • 文字列表現をレンダラーに照会する、適切に動作するkeySelectionManager

文字列プロバイダーを除くすべては、そのまま再利用できます(つまり、カスタムレンダラーとkeySelectionManagerの1つの実装です)。文字列プロバイダーf.iの一般的な実装が可能です。これらのフォーマット値またはリフレクションを介したBeanプロパティの使用。そして基本的なルールを破ることなく:-)

1
kleopatra