"Checkbox editor" 对于 JTable

"Checkbox editor" for JTable

为 JTable 添加 "checkbox editor" 的最佳方法是什么?到目前为止,我有一个使用自定义 AbstractTableModel 的 JTable,它使用两个数据集合:一个是 HashMap,它为每一行添加具有 "false" 值的复选框。第二个集合框架是带有整数的简单 ArrayList。 AbstractTableModel 还具有从 ArrayList 和 AbstractTableModel 中删除选定行的自定义方法。问题是,如果我 "check" chceckBox in table,检查的值保持在同一行。我认为问题在于重写 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();
            }
        });
    }
}

One is HashMap that add for each row checkbox with "false" value. Second collection framework is simple ArrayList with Integers

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

可以使用DefaultTableModelDefaultTableModel 允许您在每一行中存储任何类型的对象。您需要做的就是将模型的 getColumnClass(...) 方法覆盖为 return 正确的 class,然后 table 将为该列选择合适的 renderer/editor。类似于:

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);

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

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

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