我在java swing中有一个关于包含一些JCheckBox的JCombobox的问题。 问题是从不检查复选框,因为渲染器似乎只接收未选择的值;但模型确实包含已检查的值,我使用调试器进行了验证。我不知道问题出在哪里。
这是代码:
主类构造函数的一部分:
cbb_keywords = new JComboBox();
cbb_keywords.setName("cbb_keywords");
cbb_keywords.addActionListener(this);
cbb_keywords.setMaximumRowCount(5);
cbb_keywords.setRenderer(new CkbKeywordsRenderer(""));
cbbmodel = new DefaultComboBoxModel<CkbKeywordsRenderer>();
cbb_keywords.setModel(cbbmodel);
cbb_keywords.setEditable(true);
应触发JCombobox中某些JCheckbox显示的代码:
public void setKeywords(Keywords keywords) {
txf_keywords.setText(keywords.toString());
DefaultComboBoxModel model = extractComboboxModel();
for (int i = 0; i < model.getSize(); i++) {
CkbKeywordsRenderer ckbrenderer =
new CkbKeywordsRenderer(
((CkbKeywordsRenderer) model.getElementAt(i))
.getText());
if (keywords.contains(ckbrenderer.getText()))
ckbrenderer.setSelected(true);
else
ckbrenderer.setSelected(false);
}
cbb_keywords.setModel(model);
}
这种方法可能需要一些解释: *首先,“模型”填充了JTable中存储的全部关键字;每行对应一本书,每本书都包含一个关键字列表。 “模型”的填充从收集所有关键字开始,然后继续删除双打。 使用我的调试器,我看到这个字段包含4个关键字:“aventure”,“jeunesse”,“maths”,“philo”。 *然后,我测试模型的每个关键字,看它是否在书的关键词列表中(变量“关键词”)(“aventure”和“jeunesse”)。 因此,在组合框列表中,我应该有4个项目,其中2个被检查:“aventure”和“jeunesse”)。如果我在JTable中选择另一本书,则应在JCombobox中检查另外两个关键字。 *此方法已经过测试并返回了一个有效的模型:其中2个为“已选中”的4个项目
现在这里是渲染器类,它永远不会收到检查值:
public class CkbKeywordsRenderer extends JCheckBox implements ListCellRenderer,
ActionListener {
static CkbKeywordsRenderer[] elements;
public CkbKeywordsRenderer(String text) {
super(text);
}
@Override
public Component getListCellRendererComponent(JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
CkbKeywordsRenderer selectedItem = (CkbKeywordsRenderer) value;
if (isSelected) {
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
} else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
if (selectedItem != null) {
setText(selectedItem.getText());
setSelected(selectedItem.isSelected());
} else if (index == -1 && value == null) setText("abc");
return this;
}
@Override
public void actionPerformed(ActionEvent e) {
JComboBox cb = (JComboBox) e.getSource();
CkbKeywordsRenderer jcheckBox = (CkbKeywordsRenderer) cb.getSelectedItem();
jcheckBox.setSelected(!jcheckBox.isSelected());
SwingUtilities.invokeLater(new Runnable() {
public void run() {
cb.showPopup();
}
});
}
你知道问题在哪里吗?
感谢
编辑:没有答案......我试图调整我的程序(模型中没有JCOmponent),但渲染器仍然没有得到未经检查的值:
请看看这两张图片,它们总结了我的问题:
顺便说一句,这是值的类(非常简单):
public class ItemCombobox {
public String itemName;
public boolean checked;
public ItemCombobox(String itemName, boolean checked) {
this.itemName = itemName;
this.checked = checked;
}
@Override
public String toString() {
return itemName;
}
}
并在第一张图片中给出了渲染器的新代码。
感谢。
答案 0 :(得分:1)
Swing基于“模型 - 视图 - 控制器”范例。这决定了数据和视图之间的分离。
这意味着需要渲染/显示的信息和数据片段与数据本身分离。这意味着数据可以通过多种独立方式表示,具体取决于您尝试使用的方式。
这意味着,模型应该只携带数据。它永远不应该携带任何类型的UI元素。
Swing还使用“委托”范例,允许您自定义有多少UI组件呈现不同的元素。首先来看看Concepts: Editors and Renderers - 这是一个非常重要的概念,因为几乎每个地方都使用它。
您还应该查看How to use lists, writing a custom cell renderer以获取更具体的详细信息。
这是一个非常基本的示例,它使用您的ItemCombobox
作为基本构建基块来生成JList
,使用JCheckBox
作为基本渲染器显示项目
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import javax.swing.DefaultListModel;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
DefaultListModel<Item> itemListModel = new DefaultListModel<>();
itemListModel.addElement(new Item("A", false));
itemListModel.addElement(new Item("B", true));
itemListModel.addElement(new Item("C", false));
itemListModel.addElement(new Item("D", false));
itemListModel.addElement(new Item("E", true));
itemListModel.addElement(new Item("F", true));
itemListModel.addElement(new Item("G", false));
itemListModel.addElement(new Item("H", true));
JList list = new JList(itemListModel);
list.setCellRenderer(new CheckBoxListCellRenderer());
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(list));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class Item {
public String itemName;
public boolean checked;
public Item(String itemName, boolean checked) {
this.itemName = itemName;
this.checked = checked;
}
public boolean isChecked() {
return checked;
}
public String getItemName() {
return itemName;
}
@Override
public String toString() {
return itemName;
}
}
public static class CheckBoxListCellRenderer extends JCheckBox implements ListCellRenderer<Item> {
private static final Border DEFAULT_NO_FOCUS_BORDER = new EmptyBorder(1, 1, 1, 1);
public CheckBoxListCellRenderer() {
setOpaque(false);
setBorder(DEFAULT_NO_FOCUS_BORDER);
}
@Override
public Component getListCellRendererComponent(JList<? extends Item> list, Item value, int index, boolean isSelected, boolean cellHasFocus) {
setSelected(value.isChecked());
setText(value.getItemName());
Color fg = list.getForeground();
if (isSelected) {
setBackground(list.getSelectionBackground());
fg = list.getSelectionForeground();
} else {
setBackground(list.getBackground());
}
setForeground(fg);
setOpaque(isSelected);
Border border = null;
if (cellHasFocus) {
if (isSelected) {
border = UIManager.getBorder("List.focusSelectedCellHighlightBorder");
}
if (border == null) {
border = UIManager.getBorder("List.focusCellHighlightBorder");
}
} else {
border = DEFAULT_NO_FOCUS_BORDER;
}
setBorder(border);
return this;
}
}
}
但如果更改了列表中的项目,该如何更新呢?
通常情况下,我会提供自定义ListModel
来处理此问题,但是,您可以使用DefaultListModel
的{{1}}来触发列表以重新呈现指定的项目。
这个例子只是添加一个按钮,当触发时,它将改变所选项目的选定状态(如果没有选择一个,则改变第一个项目)
setElementAt
但我如何允许用户从
import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JScrollPane; import javax.swing.ListCellRenderer; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.border.Border; import javax.swing.border.EmptyBorder; public class Test { public static void main(String[] args) { new Test(); } public Test() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { ex.printStackTrace(); } DefaultListModel<Item> itemListModel = new DefaultListModel<>(); itemListModel.addElement(new Item("A", false)); itemListModel.addElement(new Item("B", true)); itemListModel.addElement(new Item("C", false)); itemListModel.addElement(new Item("D", false)); itemListModel.addElement(new Item("E", true)); itemListModel.addElement(new Item("F", true)); itemListModel.addElement(new Item("G", false)); itemListModel.addElement(new Item("H", true)); JList list = new JList(itemListModel); list.setCellRenderer(new CheckBoxListCellRenderer()); JButton change = new JButton("Change"); change.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int index = list.getSelectedIndex(); if (index == -1) { index = 0; } Item item = itemListModel.get(index); item.setChecked(!item.isChecked()); // Force an update of the specified element itemListModel.setElementAt(item, index); } }); JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new JScrollPane(list)); frame.add(change, BorderLayout.SOUTH); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class Item { public String itemName; public boolean checked; public Item(String itemName, boolean checked) { this.itemName = itemName; this.checked = checked; } public void setChecked(boolean checked) { this.checked = checked; } public boolean isChecked() { return checked; } public String getItemName() { return itemName; } @Override public String toString() { return itemName; } } public static class CheckBoxListCellRenderer extends JCheckBox implements ListCellRenderer<Item> { private static final Border DEFAULT_NO_FOCUS_BORDER = new EmptyBorder(1, 1, 1, 1); public CheckBoxListCellRenderer() { setOpaque(false); setBorder(DEFAULT_NO_FOCUS_BORDER); } @Override public Component getListCellRendererComponent(JList<? extends Item> list, Item value, int index, boolean isSelected, boolean cellHasFocus) { setSelected(value.isChecked()); setText(value.getItemName()); Color fg = list.getForeground(); if (isSelected) { setBackground(list.getSelectionBackground()); fg = list.getSelectionForeground(); } else { setBackground(list.getBackground()); } setForeground(fg); setOpaque(isSelected); Border border = null; if (cellHasFocus) { if (isSelected) { border = UIManager.getBorder("List.focusSelectedCellHighlightBorder"); } if (border == null) { border = UIManager.getBorder("List.focusCellHighlightBorder"); } } else { border = DEFAULT_NO_FOCUS_BORDER; } setBorder(border); return this; } } }
中选择/取消选择某个项?
对我来说,这就是使用JList
进行此类任务的概念开始分崩离析,因为JList
通常不是可编辑的。对我来说,I'd prefer a JTable
based solution instead,但是......
JList
此示例只是向import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
DefaultListModel<Item> itemListModel = new DefaultListModel<>();
itemListModel.addElement(new Item("A", false));
itemListModel.addElement(new Item("B", true));
itemListModel.addElement(new Item("C", false));
itemListModel.addElement(new Item("D", false));
itemListModel.addElement(new Item("E", true));
itemListModel.addElement(new Item("F", true));
itemListModel.addElement(new Item("G", false));
itemListModel.addElement(new Item("H", true));
JList list = new JList(itemListModel);
list.setCellRenderer(new CheckBoxListCellRenderer());
JButton change = new JButton("Change");
change.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int index = list.getSelectedIndex();
if (index == -1) {
index = 0;
}
Item item = itemListModel.get(index);
item.setChecked(!item.isChecked());
// Force an update of the specified element
itemListModel.setElementAt(item, index);
}
});
list.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
int index = list.locationToIndex(e.getPoint());
if (index < 0) {
return;
}
Item item = itemListModel.get(index);
item.setChecked(!item.isChecked());
// Force an update of the specified element
itemListModel.setElementAt(item, index);
}
});
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(list));
frame.add(change, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class Item {
public String itemName;
public boolean checked;
public Item(String itemName, boolean checked) {
this.itemName = itemName;
this.checked = checked;
}
public void setChecked(boolean checked) {
this.checked = checked;
}
public boolean isChecked() {
return checked;
}
public String getItemName() {
return itemName;
}
@Override
public String toString() {
return itemName;
}
}
public static class CheckBoxListCellRenderer extends JCheckBox implements ListCellRenderer<Item> {
private static final Border DEFAULT_NO_FOCUS_BORDER = new EmptyBorder(1, 1, 1, 1);
public CheckBoxListCellRenderer() {
setOpaque(false);
setBorder(DEFAULT_NO_FOCUS_BORDER);
}
@Override
public Component getListCellRendererComponent(JList<? extends Item> list, Item value, int index, boolean isSelected, boolean cellHasFocus) {
setSelected(value.isChecked());
setText(value.getItemName());
Color fg = list.getForeground();
if (isSelected) {
setBackground(list.getSelectionBackground());
fg = list.getSelectionForeground();
} else {
setBackground(list.getBackground());
}
setForeground(fg);
setOpaque(isSelected);
Border border = null;
if (cellHasFocus) {
if (isSelected) {
border = UIManager.getBorder("List.focusSelectedCellHighlightBorder");
}
if (border == null) {
border = UIManager.getBorder("List.focusCellHighlightBorder");
}
} else {
border = DEFAULT_NO_FOCUS_BORDER;
}
setBorder(border);
return this;
}
}
}
添加了MouseListener
,并更改了所点击项目的选定状态。
这有很多直接的缺点:
JList
的解决方案即可实现免费获得的功能JTable
并不是可编辑的,因此大多数用户不会有这种期望/心态,并且可能会导致用户感到沮丧,因为他们的预期结果不符合你的程序现在在做什么。此时,我说您已经超出了JList
的预期功能,使用JList
可以更好地管理这些功能