我有一个关于 JCombobox 的问题,其中包含一些 JCheckBoxes,在 java swing 中。问题是复选框永远不会被选中,因为渲染器似乎只接收未选择的值;但该模型确实包含检查值,我用调试器对其进行了验证。我不知道问题出在哪里。
这是代码:
主类构造函数的一部分:
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 个关键字:“冒险”、“婕斯”、“数学”、“philo”。* 然后,我测试模型的每个关键字,看看它是否在本书的关键字列表中(变量“关键字”)(分别是:“aventure”和“jeunesse”)。因此,在组合框的列表中,我LD有4个项目,其中2个被选中:“冒险”和“婕斯”)。如果我在JTable中选择另一本书,则应在JCombobox中选中其他2个关键字。* 此方法经过测试并返回一个有效的模型:4 个项目,其中 2 个被“选中”
现在这里是渲染器类,它永远不会收到检查值:
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),但渲染器仍然得到未经检查的值:
请看一下这 2 张图片,它们很好地总结了我的问题:
顺便说一下,这是值的类(非常简单):
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;
}
}
渲染器的新代码在第一张图片中给出。
谢谢。
Swing 基于“模型-视图-控制器”范式。这要求数据与视图之间的分离。
这意味着需要呈现/显示的信息和数据片段与数据本身分离。这意味着数据可以用多种独立的方式表示,具体取决于您尝试使用的内容。
这意味着,模型应该只携带数据。它永远不应该携带任何类型的 UI 元素。
Swing 还使用“委派”范例来允许您自定义呈现不同元素的 UI 组件数量。首先看看概念:编辑器和渲染器 - 这是一个非常重要的概念,因为它几乎在任何地方都使用。
您还应该查看如何使用列表,编写自定义单元格呈现器以获取更具体的详细信息。
这是一个非常基本的示例,它使用ItemCombobox
作为基本构建块来生成JList,该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;
}
}
}
但是,如果列表中的项目发生更改,如何更新它?
通常,我会提供一个自定义列表模型
来处理这个问题,但是,您可以使用 DefaultListModel
的 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进行此类任务的概念开始分崩离析的地方,因为JList
通常不是可编辑的。对我来说,我更喜欢基于
JTable
的解决方案,但是......
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;
}
}
}
此示例只是将鼠标侦听器
添加到 JList
,并更改所单击项的选定状态。
这有许多直接的缺点:
JTable
的解决方案免费实现功能JList
并不意味着是可编辑的,所以大多数用户不会有这种期望/心态,这可能会给用户带来挫败感,因为他们的预期结果不符合你的要求。拉姆现在正在做。在这一点上,我想说你已经超出了JList
的预期功能,通过使用JTable
可以更好地管理这些功能。