我想在Swing中创建一个多选组合框,显示由分号或其他字符分隔的用户选择的项目。
例如:
选择文章< - 显示用户的选择
选择文章
没有文章
一个
在
用户选择了“a”和“the”,“a;”将显示而不是“选择文章”。
我试过编写这样的组合,但我的问题是“选择文章”并没有被当前用户选择所取代。
你只能看到类似的东西:
选择文章< - 显示用户的选择(不替换为“a; the”)
一个;该
没有文章
一个
在
这是我的代码:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
public class MultiSelectionComboBox {
private DefaultComboBoxModel model;
private JPanel getContent() {
Object[] items = { "Select article(s)", "No article", "a", "the" };
model = new DefaultComboBoxModel(items);
JComboBox combo = new JComboBox(model);
SelectionManager manager = new SelectionManager();
manager.setNonSelectable(items[0]);
Renderer renderer = new Renderer(manager);
combo.addActionListener(manager);
combo.setRenderer(renderer);
JPanel panel = new JPanel();
panel.add(combo);
return panel;
}
class SelectionManager implements ActionListener {
JComboBox combo = null;
private List<Object> selectedItems = new ArrayList<Object>();
private Object nonSelectable;
public void setNonSelectable(Object val) {
nonSelectable = val;
}
public void actionPerformed(ActionEvent e) {
if (combo == null) {
combo = (JComboBox) e.getSource();
}
Object item = combo.getSelectedItem();
// Toggle the selection state for item.
if (selectedItems.contains(item)) {
selectedItems.remove(item);
} else if (!item.equals(nonSelectable)) {
selectedItems.add(item);
}
combo.setSelectedIndex(0);
}
public List<Object> getSelectedItems() {
return selectedItems;
}
}
class Renderer extends BasicComboBoxRenderer {
SelectionManager selectionManager;
public Renderer(SelectionManager sm) {
selectionManager = sm;
}
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
boolean cellHasFocus) {
setFont(list.getFont());
if (index == 0) { // first item shows currently selected items delimited by ;
StringBuffer firstItem = new StringBuffer();
for (Object sel : selectionManager.getSelectedItems()) {
firstItem.append(sel + "; ");
}
if (firstItem.toString().endsWith("; ")) {
firstItem.deleteCharAt(firstItem.length() - 2);
}
setText((value == null) ? "" : firstItem.toString());
} else {// other items
setText((value == null) ? "" : value.toString());
}
return this;
}
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new MultiSelectionComboBox().getContent());
f.setSize(300, 145);
f.setLocation(200, 200);
f.setVisible(true);
}
}
我知道组合不是用于多重选择,但在我的情况下,我没有看到更好的UI元素,因为我想在句子中放置这样的组合。 例如:“哪里是 | a; | 键?”
答案 0 :(得分:4)
在单元格渲染器中,假设索引0是所选值,而不是。它实际上是-1(或更准确地说,这是用于表示编辑器值的索引)
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
setFont(list.getFont());
if (index == -1 && selectionManager.getSelectedItems().size() > 0) {
StringBuffer firstItem = new StringBuffer();
for (Object sel : selectionManager.getSelectedItems()) {
firstItem.append(sel + "; ");
}
if (firstItem.toString().endsWith("; ")) {
firstItem.deleteCharAt(firstItem.length() - 2);
}
setText((value == null) ? "" : firstItem.toString());
} else {// other items
setText((value == null) ? "" : value.toString());
}
return this;
}
答案 1 :(得分:2)
您的代码的基本问题是您将模型职责(==决定选择)打包到视图(==渲染器+操作代码)中。相反,解决它们所属的位置,即模型。下面是一个非常简单的实现,只是指出方向:
@SuppressWarnings({ "unchecked", "rawtypes" })
public static class MyComboBoxModel extends AbstractListModel
implements ComboBoxModel {
public static Object NONE = "none";
List values = new ArrayList();
List selected = new ArrayList();
public MyComboBoxModel(Object... values) {
for (Object object : values) {
this.values.add(object);
}
}
@Override
public int getSize() {
return values.size();
}
@Override
public Object getElementAt(int index) {
return values.get(index);
}
@Override
public void setSelectedItem(Object anItem) {
if (anItem == null || anItem == NONE) {
if (selected.isEmpty()) return;
selected.clear();
} else {
boolean removed = selected.remove(anItem);
if (!removed) {
selected.add(anItem);
}
}
fireContentsChanged(this, -1, -1);
}
@Override
public Object getSelectedItem() {
return selected;
}
}
// use
MyComboBoxModel model = new MyComboBoxModel(MyComboBoxModel.NONE , "a", "the", "other");
model.setSelectedItem(null);
JComboBox box = new JComboBox(model);
即使使用标准渲染器,我们也可以看到它的工作原理:-)自定义渲染器可以根据需要进一步微调视觉表示 - 不包含任何与数据相关的逻辑。