33

在Java Swing中拥有一个带有复选框的项目列表的最佳方法是什么?

即一个JList,其中的项目每个都有一些文本和一个复选框?

4

9 回答 9

24

一个绝妙的答案就是这个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我链接到的问题,我会修改这个答案。

于 2009-12-27T15:07:23.977 回答
16

创建一个自定义ListCellRenderer并将其分配给JList.

此自定义必须在方法的实现中ListCellRenderer返回 a 。JCheckboxgetListCellRendererComponent(...)

但这JCheckbox将不可编辑,屏幕上的简单绘画由您选择何时JCheckbox必须“勾选”,

例如,在选择行时显示它(参数isSelected),但是如果选择更改,则不会保持检查状态。最好是查看下面的数据来显示它检查过ListModel,但随后由您来实现更改数据检查状态的方法,并将更改通知JList到要重新绘制的。

如果您需要,我稍后会发布示例代码

ListCellRenderer

于 2008-08-21T13:05:26.637 回答
13

只需实施一个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());

这将导致

CheckboxListCellRenderer 示例

自定义摆动组件渲染器中的详细信息。

PS:如果你想要无线电元素,只需替换extends JCheckboxextends JRadioButton.

于 2014-11-30T17:16:32.220 回答
11

我可能希望使用JTable而不是JList,并且由于复选框的默认呈现相当难看,我可能希望放入自定义TableModelCellRendererCellEditor来表示布尔值。当然,我想这已经做了几十亿次了。孙有很好的例子

于 2008-08-21T13:04:02.490 回答
8

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"));
于 2014-07-16T09:53:32.357 回答
3

有人已经实现了您需要的小部件或实用程序的可能性很大。大型 OSS 社区的部分好处。除非您真的想自己动手,否则无需重新发明轮子。在这种情况下,这将是一个很好的 CellRenderers 和 Editors 学习练习。

我的项目在 JIDE 上取得了巨大的成功。您想要的组件,一个复选框列表,位于 JIDE 公共层(它是 OSS,托管在 java.net 上)。商业的东西也很好,但你不需要它。

http://www.jidesoft.com/products/oss.htm https://jide-oss.dev.java.net/

于 2008-08-21T13:18:40.130 回答
3

我建议您使用 GridLayout 为 1 列的 JPanel。将复选框添加到 JPanel,并将 JPanel 设置为 JScrollPane 的数据源。要获取选中的 CheckBox,只需调用 JPanel 的 getComponents() 即可获取 CheckBox。

于 2013-09-14T15:56:51.997 回答
0

这只是 Rawa 对 JCheckBoxList 的一点补充。这将增加使用空格键进行选择的能力。如果选择了多个项目,所有将设置为第一个项目的反转值。

        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();
                }
            }
        }
        });
于 2014-08-27T07:13:46.227 回答
0

Swing 中的所有聚合组件(即组成其他组件的组件,例如 JTable、JTree 或 JComboBox)都可以进行高度定制。例如,JTable 组件通常显示 JLabel 组件的网格,但它也可以显示 JButton、JTextField 甚至其他 JTable。然而,让这些聚合组件显示非默认对象是容易的部分。由于 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 接口的等效组件更简单且更小。要使用该类,只需实例化它,然后通过调用 setListData 将 JCheckBox 对象(或 JCheckBox 对象的子类)的数组传递给它。请注意,此组件中的复选框不会响应按键(即空格键),但如果需要,您始终可以添加自己的按键侦听器。

资料来源:DevX.com

于 2015-09-22T08:26:18.810 回答