使用图像呈现 JButton 以获取 JTable 中的 JCheckBox 行为不会更新我的 table

Rendering JButton to get the JCheckBox behavior in a JTable by using images does not update my table

我正在渲染一个带有图像的 JButton,基本上是为了模拟 JCheckBox 的行为。为什么我不直接让 JTable 来呈现 JCheckbox?仅仅是因为我需要更大的复选框,而且我无法调整它们的大小(据我所知)。

所以,我有自己的 table 单元格渲染器和编辑器。两者都在其上呈现 JButton 和复选框图像。我想要做的是将图像从选中图像更改为未选中图像(反之亦然)并更新单元格值(布尔值 true 或 false)。但是,出于某种原因,getCellEditorValue() 不会更新我的 table。所以,一旦我松开鼠标,它们的价值就会回到原来的价值。

任何帮助将不胜感激!非常感谢!

    public class TableExample extends JFrame {

    JScrollPane pane;
    JPanel panel;
    JTable table;
    Object[][] data;
    MyTableModel tm;
    Renderer buttonColumn;

    public TableExample(Object[][] data) throws IOException {

        String[] columns = {"Column#1", "Column#2", "Column#3", "Column#4", "Column#5", "Column#6"};
        this.data = data;
        this.setPreferredSize(new Dimension(700, 500));
        this.setMinimumSize(new Dimension(700, 500));
        this.setMaximumSize(new Dimension(700, 500));
        tm = new MyTableModel(this.data, columns);
        this.table = new JTable(tm);
        this.table.setRowHeight(50);
        table.setDefaultRenderer(Boolean.class, new Renderer(this, table, 5));
        table.setDefaultEditor(Boolean.class, new Editor(this, table, 5));
        this.pane = new JScrollPane(this.table);
        this.add(this.pane);

    }

    /**
     *
     * TABLE MODEL
     */
    public class MyTableModel extends AbstractTableModel {

        private Object[][] data;
        private String[] columns;

        public MyTableModel(Object[][] data, String[] columns) {
            this.data = data;
            this.columns = columns;

        }

        public void setColumns(String[] columns1) {
            this.columns = columns1;
        }

        @Override
        public int getRowCount() {
            return this.data.length;
        }

        @Override
        public int getColumnCount() {
            return this.columns.length;
        }

        @Override
        public String getColumnName(int columnIndex) {
            return columns[columnIndex];
        }

        @Override
        public Class<?> getColumnClass(int c) {
            return getValueAt(0, c).getClass();
        }

        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return true;
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            return data[rowIndex][columnIndex];
        }

        public void setValueAt(String value, int row, int col) {

            if (DEBUG) {
                System.out.println("Setting value at " + row + "," + col
                        + " to " + value
                        + " (an instance of "
                        + value.getClass() + ")");
            }

            data[row][col] = value;
            fireTableCellUpdated(row, col);

            if (DEBUG) {
                System.out.println("New value of data:");
                printDebugData();
            }
        }

        private void printDebugData() {
            int numRows = getRowCount();
            int numCols = getColumnCount();

            for (int i = 0; i < numRows; i++) {
                System.out.print("    row " + i + ":");
                for (int j = 0; j < numCols; j++) {
                    System.out.print("  " + data[i][j]);
                }
                System.out.println();
            }
            System.out.println("--------------------------");
        }

    }
    /**
     *
     * CELL RENDERER
     */

    private class Renderer extends JButton implements TableCellRenderer {

        ImageIcon check;
        ImageIcon uncheck;
        boolean isChecked;

        public Renderer(JFrame frame, JTable table, int column) throws IOException {

            Image checkI = ImageIO.read(getClass().getResource("ukbuttonblue.png"));
            Image unCheckI = ImageIO.read(getClass().getResource("ukbuttonrev.png"));
            this.setBorderPainted(false);
            check = new ImageIcon(checkI);
            uncheck = new ImageIcon(unCheckI);

        }

        @Override
        public Component getTableCellRendererComponent(
                JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            this.isChecked = (boolean) value;
            if (isChecked) {
                setIcon(check);

            } else {
                setIcon(uncheck);

            }

            return this;
        }
    }

    /**
     *
     * CELL EDITOR
     */

    private class Editor extends AbstractCellEditor implements TableCellEditor, ActionListener {

        private JButton editButton;

        ImageIcon check;
        ImageIcon uncheck;
        boolean isChecked;

        public Editor(JFrame frame, JTable table, int column) throws IOException {

            editButton = new JButton();
            editButton.addActionListener(this);
            editButton.setBorderPainted(false);

            Image checkI = ImageIO.read(getClass().getResource("check.png"));
            Image unCheckI = ImageIO.read(getClass().getResource("uncheck.png"));
            check = new ImageIcon(checkI);
            uncheck = new ImageIcon(unCheckI);

        }

        @Override
        public Component getTableCellEditorComponent(
                JTable table, Object value, boolean isSelected, int row, int column) {

            this.isChecked = (boolean) value;
            if (this.isChecked) {
                editButton.setIcon(uncheck);
            } else {
                editButton.setIcon(check);
            }
            System.out.println("Edit " + isChecked);

            return editButton;

        }

        @Override
        public Object getCellEditorValue() {

            System.out.println("giden " + isChecked);
            return this.isChecked;

        }

        @Override
        public void actionPerformed(ActionEvent e) {

            if (this.isChecked) {
                this.isChecked = false;
            } else {
                this.isChecked = true;
            }

            fireEditingStopped();

        }
    }

    public static void main(String[] args) throws IOException {

        Object[][] data = {
            {"1", "Allan", "Smith", false, true, false},
            {"2", "Jerry", "Tucker", true, false, true}
        };

        TableExample app = new TableExample(data);
        app.setVisible(true);

    }
}

经过一段时间的研究后,我意识到 myTableModel 的 isCellEditable 方法无法正常工作。我只是切换到 DetafultTableModel 覆盖获取列 class。

    @Override
    public Class<?> getColumnClass(int c) {
        return getValueAt(0, c).getClass();
    }

使用 DefaultTableModel 的一个问题是布尔值 class 会自动呈现给常规 JCheckBoxes。因此,我没有使用布尔值 class,而是使用 Integer class 来简单地用 0 和 1 来模拟 true 和 false。

这是在 JTable 中使用按钮和图像模拟 JCheckBox 行为的最终程序。这为呈现不同图像提供了极大的灵活性,并且仍然获得 JCheckBox 行为。那么,尽情享受吧!

    public class TableExample extends JFrame {

    JScrollPane pane;
    JPanel panel;
    JTable table;
    Object[][] data;
    DefaultTableModel tm;
    Renderer buttonColumn;

    public TableExample(Object[][] data) throws IOException {

        String[] columns = {"Column#1", "Column#2", "Column#3", "Column#4", "Column#5", "Column#6"};
        this.data = data;
        this.setPreferredSize(new Dimension(700, 500));
        this.setMinimumSize(new Dimension(700, 500));
        this.setMaximumSize(new Dimension(700, 500));
        //tm = new DefaultTableModel(this.data, columns);
        DefaultTableModel tm = new DefaultTableModel(this.data, columns) {
            @Override
            public Class<?> getColumnClass(int c) {

                return getValueAt(0, c).getClass();
            }
        };

        this.table = new JTable(tm);
        this.table.setRowHeight(50);
        table.setDefaultRenderer(Integer.class, new Renderer(this, table, 5));
        table.setDefaultEditor(Integer.class, new Editor(this, table, 5));
        this.pane = new JScrollPane(this.table);
        this.add(this.pane);

    }

    /**
     *
     * RENDERER
     */
    private class Renderer extends JButton implements TableCellRenderer {

        ImageIcon check;
        ImageIcon uncheck;
        int isChecked;

        public Renderer(JFrame frame, JTable table, int column) throws IOException {

            Image checkI = ImageIO.read(getClass().getResource("check.png"));
            Image unCheckI = ImageIO.read(getClass().getResource("uncheck.png"));
            this.setBorderPainted(false);
            check = new ImageIcon(checkI);
            uncheck = new ImageIcon(unCheckI);

        }

        @Override
        public Component getTableCellRendererComponent(
                JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            this.isChecked = (int) value;
            if (isChecked == 1) {
                setIcon(check);

            } else {
                setIcon(uncheck);

            }

            return this;
        }
    }
    /**
     *
     * EDITOR
     */

    private class Editor extends AbstractCellEditor implements TableCellEditor, ActionListener {

        private JButton editButton;

        ImageIcon check;
        ImageIcon uncheck;
        int isChecked;

        public Editor(JFrame frame, JTable table, int column) throws IOException {

            editButton = new JButton();
            editButton.addActionListener(this);
            editButton.setBorderPainted(false);

            Image checkI = ImageIO.read(getClass().getResource("check.png"));
            Image unCheckI = ImageIO.read(getClass().getResource("uncheck.png"));
            check = new ImageIcon(checkI);
            uncheck = new ImageIcon(unCheckI);

        }

        @Override
        public Component getTableCellEditorComponent(
                JTable table, Object value, boolean isSelected, int row, int column) {

            this.isChecked = (int) value;
            if (this.isChecked == 1) {
                editButton.setIcon(uncheck);
                this.isChecked = 0;
            } else {
                editButton.setIcon(check);
                this.isChecked = 1;
            }

            return editButton;

        }

        @Override
        public Object getCellEditorValue() {

            return this.isChecked;

        }

        @Override
        public void actionPerformed(ActionEvent e) {

            fireEditingStopped();

        }

        public void updateValue() {

        }
    }

    public static void main(String[] args) throws IOException {

        Object[][] data = {
            {"1", "Allan", "Smith", false, false, 0},
            {"2", "Jerry", "Tucker", true, true, 1}
        };

        TableExample app = new TableExample(data);
        app.setVisible(true);

    }

}