TL:DR我想创建一个JComboBox
,其中JCheckboxes
代替JLabels
,但在主标签中 - 在这个地方我想保留字符串代表所有选中的值框。我设法让它工作,但是我在点击鼠标时保持菜单打开时遇到了一些麻烦。我还希望箭头键只是在框中导航而不选择要选择的项目和空格键。
无论我做什么,在我的ActionListener
捕获鼠标并选择一个项目之后,菜单通过嵌套在JComboBox
和方法setPopupVisible
中的其他一些监听器关闭 - 它适用于我的丑陋的解决方法,但必须有一个更好的方法来做到这一点..
我相信我需要listBox
课程BasicComboBoxUI
上的小鼠听众,但我该如何到达那里?
尽可能少的代码缩小到:
ComboCheckBoxModel:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class ComboCheckBoxModel extends DefaultListModel implements ComboBoxModel, ItemSelectable {
private List<String> items = new ArrayList<>();
private List<String> checkedItems = new ArrayList<>();
private String selectedItem;
public ComboCheckBoxModel(List<String> items) {
if(!items.isEmpty()) {
selectedItem = items.get(0);
}
this.items = items;
}
public void check(Object item) {
String itemAsString = item.toString();
if(checkedItems.contains(itemAsString)) {
checkedItems.remove(itemAsString);
} else {
checkedItems.add(itemAsString);
}
fireContentsChanged(this, items.indexOf(item), items.indexOf(item));
}
public String getDataStringRepresentation() {
return checkedItems.stream().sorted().collect(Collectors.joining(", "));
}
@Override
public void setSelectedItem(Object anItem) {
selectedItem = anItem.toString();
}
@Override
public Object getSelectedItem() {
return selectedItem;
}
@Override
public int getSize() {
return items.size();
}
@Override
public Object getElementAt(int index) {
return items.get(index);
}
public boolean isChecked(String stringValue) {
return checkedItems.contains(stringValue);
}
@Override
public Object[] getSelectedObjects() {
return items.toArray();
}
@Override
public void addItemListener(ItemListener l) {
}
@Override
public void removeItemListener(ItemListener l) {
}
}
的JComboBox:
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.stream.Stream;
import static java.util.stream.Collectors.toList;
public class JComboCheckBox extends JComboBox {
private final ComboCheckBoxModel model = new ComboCheckBoxModel(Stream.of("bum", "kabum", "dabum").collect(toList()));
private boolean shouldntClose;
public JComboCheckBox() {
super();
setRenderer(new CheckBoxCellRenderer());
setModel(model);
addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (e.getModifiers() == InputEvent.BUTTON1_MASK) {
System.out.println("LPM MASK");
model.check(model.getSelectedItem());
shouldntClose = true;
}
}
});
}
@Override
protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
if (ks.getKeyCode() == KeyEvent.VK_SPACE && isPopupVisible()) {
if (ks.getKeyCode() == KeyEvent.VK_SPACE && condition == WHEN_FOCUSED && ks.isOnKeyRelease()) {
System.out.println("ks = [" + ks + "], e = [" + e + "], condition = [" + condition + "], pressed = [" + pressed + "]");
model.check(model.getSelectedItem());
}
return true;
}
return super.processKeyBinding(ks, e, condition, pressed);
}
@Override
public void setPopupVisible(boolean v) {
if (shouldntClose) {
shouldntClose = false;
return;
} else {
super.setPopupVisible(v);
}
}
@Override
public Object getSelectedItem() {
return model.getSelectedItem();
}
}
细胞渲染器:
import javax.swing.*;
import java.awt.*;
public class CheckBoxCellRenderer extends JCheckBox implements ListCellRenderer {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
ComboCheckBoxModel model = (ComboCheckBoxModel) list.getModel();
if (index != -1) {
String stringValue = value == null ? "null" : value.toString();
setText(stringValue);
boolean checked = model.isChecked(stringValue);
setSelected(checked);
if (isSelected) {
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
} else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
return this;
} else {
String stringValue = model.getDataStringRepresentation();
return new JLabel(stringValue);
}
}
}
发射器:
import javax.swing.*;
public class Launcher {
public JFrame create() {
JFrame f=new JFrame("Type the name of frame");
f.add(new JComboCheckBox());
f.setSize(400,400);
return f;
}
public static void main(String[] args) {
Launcher launcher = new Launcher();
launcher.create().setVisible(true);
}
}
答案 0 :(得分:0)
类BasicComboBoxUI中的listBox但是我如何到达那里?
listBox(JList
?)可以从BasicComboPopup
获取:
Accessible a = getAccessibleContext().getAccessibleChild(0);
if (a instanceof BasicComboPopup) {
BasicComboPopup pop = (BasicComboPopup) a;
int index = pop.getList().getSelectedIndex();
//...
}
的 ComboCheckBoxTest.java 强>
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;
import javax.accessibility.*;
import javax.swing.*;
import javax.swing.plaf.basic.*;
public class ComboCheckBoxTest {
public JComponent makeUI() {
CheckableItem[] m = {
new CheckableItem("bum", false),
new CheckableItem("kabum", false),
new CheckableItem("dabum", false)
};
JPanel p = new JPanel();
p.add(new JComboCheckBox<CheckableItem>(m));
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
JFrame f = new JFrame("Type the name of frame");
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new ComboCheckBoxTest().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}
class CheckableItem {
public final String text;
public boolean selected;
protected CheckableItem(String text, boolean selected) {
this.text = text;
this.selected = selected;
}
@Override public String toString() {
return text;
}
}
class CheckBoxCellRenderer<E extends CheckableItem> implements ListCellRenderer<E> {
private final JLabel label = new JLabel(" ");
private final JCheckBox check = new JCheckBox(" ");
@Override public Component getListCellRendererComponent(
JList list, CheckableItem value, int index,
boolean isSelected, boolean cellHasFocus) {
ListModel model = list.getModel();
if (index < 0) {
label.setText(getDataStringRepresentation(model));
return label;
} else {
check.setText(Objects.toString(value, "null"));
check.setSelected(value.selected);
if (isSelected) {
check.setBackground(list.getSelectionBackground());
check.setForeground(list.getSelectionForeground());
} else {
check.setBackground(list.getBackground());
check.setForeground(list.getForeground());
}
return check;
}
}
private String getDataStringRepresentation(ListModel model) {
List<String> sl = new ArrayList<>();
for (int i = 0; i < model.getSize(); i++) {
Object o = model.getElementAt(i);
if (o instanceof CheckableItem && ((CheckableItem) o).selected) {
sl.add(o.toString());
}
}
return sl.stream().sorted().collect(Collectors.joining(", "));
}
}
class JComboCheckBox<E extends CheckableItem> extends JComboBox<E> {
private boolean shouldntClose;
private transient ActionListener listener;
public JComboCheckBox() {
super();
}
public JComboCheckBox(E[] m) {
super(m);
}
@Override public Dimension getPreferredSize() {
return new Dimension(200, 20);
}
@Override public void updateUI() {
setRenderer(null);
removeActionListener(listener);
super.updateUI();
listener = e -> {
if (e.getModifiers() == InputEvent.BUTTON1_MASK) {
System.out.println("LPM MASK: " + getSelectedIndex());
updateItem(getSelectedIndex());
shouldntClose = true;
}
};
setRenderer(new CheckBoxCellRenderer<CheckableItem>());
addActionListener(listener);
getInputMap(JComponent.WHEN_FOCUSED).put(
KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "space-key-select");
getActionMap().put("space-key-select", new AbstractAction() {
@Override public void actionPerformed(ActionEvent e) {
System.out.println("JComboBox#getSelectedIndex()" + getSelectedIndex());
Accessible a = getAccessibleContext().getAccessibleChild(0);
if (a instanceof BasicComboPopup) {
BasicComboPopup pop = (BasicComboPopup) a;
int i = pop.getList().getSelectedIndex();
System.out.println("JList#getSelectedIndex() " + i);
updateItem(i);
}
}
});
}
private void updateItem(int index) {
if (isPopupVisible()) {
E item = getItemAt(index);
item.selected ^= true;
removeItemAt(index);
insertItemAt(item, index);
setSelectedItem(item);
}
}
@Override
public void setPopupVisible(boolean v) {
if (shouldntClose) {
shouldntClose = false;
return;
} else {
super.setPopupVisible(v);
}
}
}