Как мне сделать список с флажками в Java Swing?
Что было бы лучшим способом иметь список элементов с флажком каждый в Java Swing?
Т.е. JList с элементами, которые имеют некоторый текст и флажок каждый?
11 ответов
Создать кастом ListCellRenderer
и назначить его JList
,
Этот обычай ListCellRenderer
должен вернуть JCheckbox
в осуществлении getListCellRendererComponent(...)
метод.
Но это JCheckbox
не будет редактируемым, это простая краска на экране, вы можете выбрать, когда это JCheckbox
должен быть отмечен или нет,
Например, показывать галочку при выборе строки (параметр isSelected
), но в этом случае статус проверки не будет поддерживаться, если выбор будет изменен. Лучше показать это проверено, сверяясь с данными ниже ListModel
, но затем вам нужно реализовать метод, который изменяет статус проверки данных, и уведомить об изменении JList
быть перекрашенным.
Я опубликую пример кода позже, если вам это нужно
Прекрасный ответ это CheckBoxList
, Он реализует ответ Telcontar (хотя за 3 года до этого:))... Я использую его в Java 1.6 без проблем. Я также добавил addCheckbox
такой метод (конечно, может быть короче, я не использовал Java в течение некоторого времени):
public void addCheckbox(JCheckBox checkBox) {
ListModel currentList = this.getModel();
JCheckBox[] newList = new JCheckBox[currentList.getSize() + 1];
for (int i = 0; i < currentList.getSize(); i++) {
newList[i] = (JCheckBox) currentList.getElementAt(i);
}
newList[newList.length - 1] = checkBox;
setListData(newList);
}
Я опробовал демо для Jidesoft, играя с CheckBoxList
Я столкнулся с некоторыми проблемами (поведение, которое не работало). Я изменю этот ответ, если обнаружу проблемы с CheckBoxList
Я связался с.
Просто внедрите ListCellRenderer
public class CheckboxListCellRenderer extends JCheckBox implements ListCellRenderer {
public Component getListCellRendererComponent(JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
setComponentOrientation(list.getComponentOrientation());
setFont(list.getFont());
setBackground(list.getBackground());
setForeground(list.getForeground());
setSelected(isSelected);
setEnabled(list.isEnabled());
setText(value == null ? "" : value.toString());
return this;
}
}
и установить рендер
JList list = new JList();
list.setCellRenderer(new CheckboxListCellRenderer());
это приведет к
Подробности в пользовательских компонентах рендеринга свинга.
PS: если хотите радиоэлементы просто замените extends JCheckbox
с extends JRadioButton
,
Я, вероятно, хотел бы использовать JTable, а не JList, и поскольку рендеринг флажка по умолчанию довольно уродлив, я бы, вероятно, хотел бы добавить пользовательские TableModel, CellRenderer и CellEditor для представления логического значения. Конечно, я бы предположил, что это было сделано уже несколько раз. У Солнца есть хорошие примеры.
Лучшее решение для Java 7 и новее
Я наткнулся на этот вопрос и понял, что некоторые из ответов довольно старые и устаревшие. В настоящее время JList является универсальным, и поэтому существуют лучшие решения.
Мое решение универсального JCheckBoxList:
import java.awt.Component;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.event.*;
@SuppressWarnings("serial")
public class JCheckBoxList extends JList<JCheckBox> {
protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
public JCheckBoxList() {
setCellRenderer(new CellRenderer());
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
int index = locationToIndex(e.getPoint());
if (index != -1) {
JCheckBox checkbox = (JCheckBox) getModel().getElementAt(index);
checkbox.setSelected(!checkbox.isSelected());
repaint();
}
}
});
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
public JCheckBoxList(ListModel<JCheckBox> model){
this();
setModel(model);
}
protected class CellRenderer implements ListCellRenderer<JCheckBox> {
public Component getListCellRendererComponent(
JList<? extends JCheckBox> list, JCheckBox value, int index,
boolean isSelected, boolean cellHasFocus) {
JCheckBox checkbox = value;
//Drawing checkbox, change the appearance here
checkbox.setBackground(isSelected ? getSelectionBackground()
: getBackground());
checkbox.setForeground(isSelected ? getSelectionForeground()
: getForeground());
checkbox.setEnabled(isEnabled());
checkbox.setFont(getFont());
checkbox.setFocusPainted(false);
checkbox.setBorderPainted(true);
checkbox.setBorder(isSelected ? UIManager
.getBorder("List.focusCellHighlightBorder") : noFocusBorder);
return checkbox;
}
}
}
Для динамического добавления списков JCheckBox вам нужно создать свою собственную ListModel или добавить DefaultListModel.
DefaultListModel<JCheckBox> model = new DefaultListModel<JCheckBox>();
JCheckBoxList checkBoxList = new JCheckBoxList(model);
DefaultListModel являются общими, и поэтому вы можете использовать методы, указанные в JAVA 7 API, вот так:
model.addElement(new JCheckBox("Checkbox1"));
model.addElement(new JCheckBox("Checkbox2"));
model.addElement(new JCheckBox("Checkbox3"));
Я рекомендую вам использовать JPanel с GridLayout 1 столбца. Добавьте флажки в JPanel и установите JPanel в качестве источника данных JScrollPane. А чтобы получить выбранные CheckBoxes, просто вызовите getComponents() JPanel, чтобы получить CheckBoxes.
Хорошие шансы с Java, что кто-то уже реализовал нужный вам виджет или утилиту. Часть преимуществ большого сообщества OSS. Не нужно изобретать велосипед, если вы действительно не хотите делать это самостоятельно. В этом случае это будет хорошим обучающим упражнением в CellRenderers и Editors.
Мой проект имел большой успех с JIDE. Требуемый компонент, список флажков, находится на общем уровне JIDE (который является OSS и размещен на java.net). Коммерческий материал тоже хорош, но он вам не нужен.
http://www.jidesoft.com/products/oss.htm https://jide-oss.dev.java.net/
Мне не нравятся решения, которые помещают флажок в модель. Модель должна содержать только данные, а не элементы отображения.
Я нашел это http://www.java2s.com/Tutorials/Java/Swing_How_to/JList/Create_JList_of_CheckBox.htm
который я немного оптимизировал. Флаг ACTIVE представляет собой флажок, флаг SELECTED показывает, на какой записи находится курсор.
моя версия требует рендерера
import java.awt.Component;
import javax.swing.JCheckBox;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
class CheckListRenderer extends JCheckBox implements ListCellRenderer<Entity> {
@Override
public Component getListCellRendererComponent(JList<? extends Entity> list,
Entity value, int index, boolean isSelected, boolean cellHasFocus) {
setEnabled(list.isEnabled());
setSelected(value.isActive()); // sets the checkbox
setFont(list.getFont());
if (isSelected) { // highlights the currently selected entry
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
} else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
setText(value.toString()+" - A" + value.isActive()+" - F"+cellHasFocus+" - S"+isSelected );
return this;
}
}
и сущность, получившая активное поле:
public class Entity {
private boolean active = true;
public boolean isActive() {
return active;
}
public void setActive(boolean isActive) {
this.active = isActive;
}
}
Теперь вам нужно только добавить это в свой JList:
list = new JList<Entity>();
list.setModel(new DefaultListModel<Entity>());
list.setCellRenderer(new CheckListRenderer());
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent event) {
if (event.getX() < 20) {
// Quick and dirty: only change the tick if clicked into the leftmost pixels
@SuppressWarnings("unchecked")
JList<Entity> list = ((JList<Entity>) event.getSource());
int index = list.locationToIndex(event.getPoint());// Get index of item clicked
if (index >= 0) {
Entity item = (Entity) list.getModel().getElementAt(index);
item.setActive(!item.isActive()); // Toggle selected state
list.repaint(list.getCellBounds(index, index));// Repaint cell
}
}
}
});
это еще один пример создания списка с флажками
class JCheckList<T> extends JList<T> {
protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
public void setSelected(int index) {
if (index != -1) {
JCheckBox checkbox = (JCheckBox) getModel().getElementAt(index);
checkbox.setSelected(
!checkbox.isSelected());
repaint();
}
}
protected static class CellListener
extends DefaultListModel
implements ListDataListener {
ListModel ls;
public CellListener(ListModel ls) {
ls.addListDataListener(this);
int i = ls.getSize();
for (int v = 0; v < i; v++) {
var r = new JCheckBox();
r.setText(ls.getElementAt(v).toString());
this.addElement(r);
}
this.ls = ls;
}
@Override
public void intervalAdded(ListDataEvent e) {
int begin = e.getIndex0();
int end = e.getIndex1();
for (; begin <= end; begin++) {
var r = new JCheckBox();
r.setText(ls.getElementAt(begin).toString());
this.add(begin, r);
}
}
@Override
public void intervalRemoved(ListDataEvent e) {
int begin = e.getIndex0();
int end = e.getIndex1();
for (; begin <= end; end--) {
this.remove(begin);
}
}
@Override
public void contentsChanged(ListDataEvent e) {
}
}
public JCheckList() {
setCellRenderer(new CellRenderer());
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
int index = locationToIndex(e.getPoint());
setSelected(index);
}
}
);
addKeyListener(new KeyListener(){
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE){
int index = JCheckList.this.getSelectedIndex();
setSelected(index);
}
}
@Override
public void keyReleased(KeyEvent e) {
}
});
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
@Override
public void setModel(ListModel<T> d) {
var r = new CellListener(d);
d.addListDataListener(r);
super.setModel(r);
}
protected class CellRenderer implements ListCellRenderer {
public Component getListCellRendererComponent(
JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
JCheckBox checkbox = (JCheckBox) value;
checkbox.setBackground(isSelected
? getSelectionBackground() : getBackground());
checkbox.setForeground(isSelected
? getSelectionForeground() : getForeground());
checkbox.setEnabled(isEnabled());
checkbox.setFont(getFont());
checkbox.setFocusPainted(false);
checkbox.setBorderPainted(true);
checkbox.setBorder(isSelected
? UIManager.getBorder(
"List.focusCellHighlightBorder") : noFocusBorder);
return checkbox;
}
}
}
Все агрегатные компоненты в Swing, то есть компоненты, состоящие из других компонентов, таких как JTable, JTree или JComboBox, могут быть настроены индивидуально. Например, компонент JTable обычно отображает сетку компонентов JLabel, но он также может отображать JButtons, JTextFields или даже другие JTables. Однако получить эти агрегатные компоненты для отображения объектов не по умолчанию. Заставить их правильно реагировать на события клавиатуры и мыши - гораздо более сложная задача из-за разделения компонентов Swing на "средства визуализации" и "редакторы". Это разделение было (на мой взгляд) неудачным выбором дизайна и только усложняет ситуацию при попытке расширить компоненты Swing.
Чтобы понять, что я имею в виду, попробуйте улучшить компонент Swing JList, чтобы он отображал флажки вместо меток. Согласно философии Swing, эта задача требует реализации двух интерфейсов: ListCellRenderer (для рисования флажков) и CellEditor (для обработки событий клавиатуры и мыши на флажках). Реализация интерфейса ListCellRenderer достаточно проста, но интерфейс CellEditor может быть довольно неуклюжим и трудным для понимания. В этом конкретном случае я бы предложил полностью забыть CellEditor и напрямую обрабатывать входные события, как показано в следующем коде.
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
public class CheckBoxList extends JList
{
protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
public CheckBoxList()
{
setCellRenderer(new CellRenderer());
addMouseListener(new MouseAdapter()
{
public void mousePressed(MouseEvent e)
{
int index = locationToIndex(e.getPoint());
if (index != -1) {
JCheckBox checkbox = (JCheckBox)
getModel().getElementAt(index);
checkbox.setSelected(
!checkbox.isSelected());
repaint();
}
}
}
);
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
protected class CellRenderer implements ListCellRenderer
{
public Component getListCellRendererComponent(
JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus)
{
JCheckBox checkbox = (JCheckBox) value;
checkbox.setBackground(isSelected ?
getSelectionBackground() : getBackground());
checkbox.setForeground(isSelected ?
getSelectionForeground() : getForeground());
checkbox.setEnabled(isEnabled());
checkbox.setFont(getFont());
checkbox.setFocusPainted(false);
checkbox.setBorderPainted(true);
checkbox.setBorder(isSelected ?
UIManager.getBorder(
"List.focusCellHighlightBorder") : noFocusBorder);
return checkbox;
}
}
}
Здесь я перехватываю щелчки мышью из списка и моделирую щелчок на соответствующем флажке. В результате получается компонент "CheckBoxList", который проще и меньше, чем эквивалентный компонент, использующий интерфейс CellEditor. Чтобы использовать класс, просто создайте его экземпляр, а затем передайте ему массив объектов JCheckBox (или подклассов объектов JCheckBox), вызвав setListData. Обратите внимание, что флажки в этом компоненте не будут реагировать на нажатия клавиш (например, пробел), но вы всегда можете добавить свой собственный слушатель клавиш, если это необходимо.
Источник: DevX.com
Вот лишь небольшое дополнение к JCheckBoxList от Rawa. Это добавит возможность выбора с помощью пробела. Если выбрано несколько элементов, для всех будет установлено инвертированное значение первого элемента.
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
int index = getSelectedIndex();
if (index != -1 && e.getKeyCode() == KeyEvent.VK_SPACE) {
boolean newVal = !((JCheckBox) (getModel()
.getElementAt(index))).isSelected();
for (int i : getSelectedIndices()) {
JCheckBox checkbox = (JCheckBox) getModel()
.getElementAt(i);
checkbox.setSelected(newVal);
repaint();
}
}
}
});