item1 と item2 を含む jcombobox があり、jtextfield もあります。jcombobox で item1 を選択すると、jtextfield に 30 が表示され、Item2 が選択された場合は 40 になります...どうすればよいですか?
3 に答える
これが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);
}
});
}
}
簡単な解決策は、を使用すること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
、より正しいアプローチである aを使用しました。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;
}
}
}
元の質問への回答ではありませんが、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 環境では間違っています。現在、モデルにはデータが含まれていませんが、ビューの理由で導入されたラッパーが含まれています。これは、懸念とカプセル化の分離を壊しています (モデルと対話するすべてのクラスは、ラップされたデータを認識する必要があります)。
ルール違反の原動力は次のとおりです。
- デフォルトの KeySelectionManager の機能を保持します (これはカスタム レンダラーによって壊れています)。
- ラッパー クラスの再利用 (任意のデータ型に適用可能)
Swing のように、カスタム レンダラーは、カスタムの視覚的表現に対応するように設計された小さなコインです。対応できないデフォルト マネージャーは ... 壊れています。このようなくだらないデフォルトに対応するためだけに設計を微調整することは、逆さまのような間違った方法です。正しいのは、対処マネージャーを実装することです。
再利用は問題ありませんが、基本的なアーキテクチャを壊すという代償を払って再利用するのは得策ではありません。
プレゼンテーション領域に問題があります。まさにその問題を解決するように設計された要素を使用して、プレゼンテーション領域で解決しましょう。ご想像のとおり、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 つの実装です)。文字列プロバイダーの一般的な実装があり、それらのフォーマット値またはリフレクションを介した Bean プロパティの使用があります。そして、すべて基本的なルールを破ることなく:-)