我已阅读文档和教程,并在此处搜索,但无济于事。
Oracle tutorial: how to use custom render for ComboBox
Another question similar with a somehow vague answer
我认为这很重要,因为很多人都在询问它,但没有人可以提供一个简单,可行的例子。所以我必须自己问一下:
我们如何使用下拉菜单制作组合框,允许我们选择多个选项?
什么不起作用:
JList
在这里无用,因为我无法在下拉菜单中显示它。 CheckBoxList
。我在组合的下拉菜单中创建了一个带复选框的SCCEE,但是复选框拒绝被选中,框中的检查丢失。
我们如何实现这一目标?
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.List;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultListModel;
import javax.swing.DefaultListSelectionModel;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.TableColumn;
public class ComboOfCheckBox extends JFrame {
public ComboOfCheckBox() {
begin();
}
private void begin() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
JTable table = new JTable(new Object[2][2], new String[]{"COL1", "COL2"});
final JCheckBox chx1 = new JCheckBox("Oh");
final JCheckBox chx2 = new JCheckBox("My");
final JCheckBox chx3 = new JCheckBox("God");
String[] values = new String[] {"Oh", "My", "God"};
JCheckBox[] array = new JCheckBox[] {chx1, chx2, chx3};
final JComboBox<JCheckBox> comboBox = new JComboBox<JCheckBox>(array) {
@Override
public void setPopupVisible(boolean visible){
if (visible) {
super.setPopupVisible(visible);
}
}
};
class CheckBoxRenderer implements ListCellRenderer {
private boolean[] selected;
private String[] items;
public CheckBoxRenderer(String[] items) {
this.items = items;
this.selected = new boolean[items.length];
}
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
boolean cellHasFocus) {
JLabel label = null;
JCheckBox box = null;
if (value instanceof JCheckBox) {
label = new JLabel(((JCheckBox)value).getText());
box = new JCheckBox(label.getText());
}
return box;
}
public void setSelected(int i, boolean selected) {
this.selected[i] = selected;
}
}
comboBox.setRenderer(new CheckBoxRenderer(values));
panel.add(comboBox);
panel.add(new JCheckBox("Another"));
getContentPane().add(panel);
pack();
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
ComboOfCheckBox frame = new ComboOfCheckBox();
}
});
}
}
答案 0 :(得分:2)
这是一个部分答案。它没有解决弹出窗口上ComboBox屏蔽事件的问题,但它确实可以解决它。问题仍然是ComboBox将一个项目上的每个选择视为另一个项目的取消选择。但是,您遇到的一个问题是,由于每次重绘时都会调用渲染器,因此您的CheckBox不是持久的 - Map
地址。{/ p>
public class ComboOfCheckBox extends JFrame {
public ComboOfCheckBox() {
begin();
}
private void begin() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
JTable table = new JTable(new Object[2][2], new String[]{"COL1", "COL2"});
String[] values = new String[] {"Oh", "My", "God"};
final JComboBox<String> comboBox = new JComboBox<String>(values) {
@Override
public void setPopupVisible(boolean visible){
if (visible) {
super.setPopupVisible(visible);
}
}
};
class CheckBoxRenderer implements ListCellRenderer<Object> {
private Map<String, JCheckBox> items = new HashMap<>();
public CheckBoxRenderer(String[] items) {
for (String item : items) {
JCheckBox box = new JCheckBox(item);
this.items.put(item, box);
}
}
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected,
boolean cellHasFocus) {
if (items.containsKey(value)) {
return items.get(value);
} else {
return null;
}
}
public void setSelected(String item, boolean selected) {
if (item.contains(item)) {
JCheckBox cb = items.get(item);
cb.setSelected(selected);
}
}
}
final CheckBoxRenderer renderer = new CheckBoxRenderer(values);
comboBox.setRenderer(renderer);
comboBox.addItemListener(e -> {
String item = (String) e.getItem();
if (e.getStateChange() == ItemEvent.DESELECTED) {
renderer.setSelected(item, false);
} else {
renderer.setSelected(item, true);
}
});
panel.add(comboBox);
panel.add(new JCheckBox("Another"));
getContentPane().add(panel);
pack();
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
ComboOfCheckBox frame = new ComboOfCheckBox();
}
});
}
}
答案 1 :(得分:0)
我也找到了解决办法,但使用了ActionListener
。事实是你不能在JCheckBox
上直接听,因为渲染在每个周期都会创建一个新的,而Piotr Wilkin的解决方案也解决了这个问题。您还可以使用此解决方案,在单击JComboBox
时检查鼠标的位置:
comboBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JComboBox combo = (JComboBox) e.getSource();
int y = MouseInfo.getPointerInfo().getLocation().y - combo.getLocationOnScreen().y;
int item = y / combo.getHeight();
((CheckBoxRenderer) combo.getRenderer()).selected[item] = !((CheckBoxRenderer) combo.getRenderer()).selected[item];
}
});
另外,在getListCellRendererComponent
方法中,您需要检查index >= 0
,因为首次创建渲染器时,由于selected
数组为空,因此会抛出错误。 :)
答案 2 :(得分:0)
您忘记了与comboBox关联的动作侦听器。另一方面,每次选择其他项时都会调用CheckBoxRenderer
,因此,如果将JCheckBox
对象作为JComboBox
项,则必须从外部更改其状态(是否选中) ,这意味着从comboBox的动作侦听器中调用的方法。但是您可以使用CheckBoxRenderer
的自动调用,在这里,我编写了一个简单的代码来向您展示如何执行此操作:
public class ComboOfChechBox extends JFrame {
public ComboOfChechBox() {
begin();
}
//a custom item for comboBox
public class CustomerItem {
public String label;
public boolean status;
public CustomerItem(String label, boolean status) {
this.label = label;
this.status = status;
}
}
//the class that implements ListCellRenderer
public class RenderCheckComboBox implements ListCellRenderer {
//a JCheckBox is associated for one item
JCheckBox checkBox;
Color selectedBG = new Color(112, 146, 190);
public RenderCheckComboBox() {
this.checkBox = new JCheckBox();
}
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
boolean cellHasFocus) {
//recuperate the item value
CustomerItem value_ = (CustomerItem) value;
if (value_ != null) {
//put the label of item as a label for the associated JCheckBox object
checkBox.setText(value_.label);
//put the status of item as a status for the associated JCheckBox object
checkBox.setSelected(value_.status);
}
if (isSelected) {
checkBox.setBackground(Color.GRAY);
} else {
checkBox.setBackground(Color.WHITE);
}
return checkBox;
}
}
private void begin() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
JComboBox<CustomerItem> combo = new JComboBox<CustomerItem>() {
@Override
public void setPopupVisible(boolean visible) {
if (visible) {
super.setPopupVisible(visible);
}
}
};
CustomerItem[] items = new CustomerItem[3];
items[0] = new CustomerItem("oh", false);
items[1] = new CustomerItem("My", false);
items[2] = new CustomerItem("God", false);
combo.setModel(new DefaultComboBoxModel<CustomerItem>(items));
combo.setRenderer(new RenderCheckComboBox());
//the action listener that you forget
combo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
CustomerItem item = (CustomerItem) ((JComboBox) ae.getSource()).getSelectedItem();
item.status = !item.status;
// update the ui of combo
combo.updateUI();
//keep the popMenu of the combo as visible
combo.setPopupVisible(true);
}
});
panel.add(combo);
panel.add(new JCheckBox("Another"));
getContentPane().add(panel);
pack();
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new ComboOfChechBox();
}
});
}
}