【问题标题】:"Checkbox editor" for JTableJTable 的“复选框编辑器”
【发布时间】:2017-04-01 08:07:50
【问题描述】:

为 JTable 添加“复选框编辑器”的最佳方法是什么?到目前为止,我有一个使用自定义 AbstractTableModel 的 JTable,它使用两个数据集合:一个是 HashMap,它为每一行添加带有“false”值的复选框。第二个集合框架是带有整数的简单 ArrayList。 AbstractTableModel 也有自定义方法从 ArrayList 和 AbstractTableModel 中删除选定的行。问题是,如果我在表中“检查”检查框,检查的值将保持在同一行。我认为问题在于覆盖 setValueAt。我的一段代码:

package checkboxeditor;

import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
import javax.swing.JButton;

public class CheckBoxEditor extends JPanel {

    public CheckBoxEditor() {
        super(new BorderLayout());

        MyTableModel myTableModel = new MyTableModel();
        JTable table = new JTable(myTableModel);
        table.setFillsViewportHeight(true);

        JButton deleteBtn = new JButton("Delete selected rows");
        deleteBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                int rowCount = table.getRowCount();
                for (int i = rowCount - 1; i >= 0; i--) {
                    boolean checked = (boolean) table.getValueAt(i, 0);
                    if (checked) {
                        myTableModel.removeRow((int) table.getValueAt(i, 1));
                    }
                }
            }
        });
        add(deleteBtn, BorderLayout.PAGE_START);

        //Create the scroll pane and add the table to it.
        JScrollPane scrollPane = new JScrollPane(table);

        //Add the scroll pane to this panel.
        add(scrollPane, BorderLayout.CENTER);
    }

    class MyTableModel extends AbstractTableModel {

        // column names
        private String[] columnNames = {"#", "Number"};
        // check boxes
        HashMap<Integer, Boolean> checkBoxes = new HashMap();
        // data
        ArrayList<Integer> data = new ArrayList();

        public MyTableModel() {
            for (Integer i = 1; i < 6; i++) {
                data.add(i);
            }

        }

        public void removeRow(Integer numberToDelete) {
            int index = data.indexOf(numberToDelete);
            data.remove(numberToDelete);
            fireTableRowsDeleted(index, index);
        }

        public int getColumnCount() {
            return columnNames.length;
        }

        public int getRowCount() {
            return data.size();
        }

        public String getColumnName(int col) {
            return columnNames[col];
        }

        public Object getValueAt(int row, int col) {
            switch (col) {
                case 0:
                    Object value = checkBoxes.get(row);
                    return (value == null) ? false : value;
                case 1:
                    return data.get(row);
                default:
                    return "";
            }
        }

        /*
         * JTable uses this method to determine the default renderer/
         * editor for each cell.  If we didn't implement this method,
         * then the last column would contain text ("true"/"false"),
         * rather than a check box.
         */
        public Class getColumnClass(int col) {
            switch (col) {
                case 0:
                    return Boolean.class;
                default:
                    return Integer.class;
            }
        }

        /*
         * Don't need to implement this method unless your table's
         * editable.
         */
        public boolean isCellEditable(int row, int col) {
            //Note that the data/cell address is constant,
            //no matter where the cell appears onscreen.
            return (col == 0);
        }

        /*
         * Don't need to implement this method unless your table's
         * data can change.
         */
        public void setValueAt(Object value, int row, int col) {
            if (col == 0) {
                checkBoxes.put(row, (boolean) value);
            }
        }

    }

    /**
     * Create the GUI and show it. For thread safety, this method should be
     * invoked from the event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("TableDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        CheckBoxEditor newContentPane = new CheckBoxEditor();
        newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);

        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

【问题讨论】:

  • Problem is that if I "check" chceckBox in table, the checked value stays in same row. 你能进一步解释问题是什么吗?我在您的代码中没有看到任何会影响复选框值的明显内容,并且在运行您的代码时,我没有看到复选框中出现异常行为。
  • @copeg,问题是复选框的“已检查”值始终用于行的索引,而不是用于应该删除值的行。例如,如果表有 5 行,并且我想删除索引为 2 的数字 3,则该值保留在索引 2 上。现在在索引 2 上有下一个数字 - 数字 4。这个数字共享行。

标签: java swing checkbox jtable


【解决方案1】:

一个是HashMap,它为每一行添加“false”值的复选框。第二个收集框架是简单的带有整数的 ArrayList

不需要两个数据结构或创建自定义TableModel。

您可以使用DefaultTableModelDefaultTableModel 允许您在每一行中存储任何类型的对象。您需要做的就是覆盖模型的getColumnClass(...) 方法以返回正确的类,并且表格将为列选择适当的渲染器/编辑器。比如:

String[] columnNames = {"#", "Number"};
DefaultTableModel model = new DefaultTableModel(columnNames, 0)
{
    //  Returning the Class of each column will allow different
    //  renderers and editors to be used based on Class

    public Class getColumnClass(int column)
    {
        return column == 0 ? Boolean.class : Integer.class;
    }
};

JTable table = new JTable(model);

然后您可以通过执行以下操作将数据添加到表中:

for (Integer i = 1; i < 6; i++) 
{
    Object[] row = {Boolean.FALSE, i};
    model.addRow( row);
} 

DefaultTableModel 已经支持从模型中删除行的方法。

【讨论】:

  • 谢谢,它比abstracttablemodel好得多。
  • 另外我想问一下,DefaultTableModel和AbstractTableModel之间有什么规则或者如何选择吗?
  • @Jan444444,DefaultTableModel 是一个功能齐全的模型,具有数据存储和功能,您只需要调整上述一些方法。当您要显示的数据不是 DefaultTableModel 可以处理的格式时,您可以使用自定义 AbstractModel。例如,您想在 TableModel 中显示自定义对象。查看Row Table Model 获取此方法的示例。
猜你喜欢
  • 2015-01-13
  • 2015-03-17
  • 1970-01-01
  • 1970-01-01
  • 2012-10-30
  • 2014-12-17
  • 1970-01-01
  • 2021-09-05
  • 1970-01-01
相关资源
最近更新 更多