我有一个包含 item1 和 item2 的 jcombobox,还有一个 jtextfield .. 当我在我的 jcombobox 上选择 item1 时,我希望 30 出现在我的 jtextfield 上,而如果选择了 Item2 则为 40... 我该怎么做?
3 回答
这就是使用 ActionLIsener 的方式
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
更正确的方法,然后变得懒惰和压倒一切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 的一种实现)。可以有字符串提供程序的一般实现,那些格式化值或通过反射使用 bean 属性。所有这些都没有违反基本规则:-)