JXTable: use a TableCellEditor and TableCellRenderer for a specific cell instead of the whole column

∥☆過路亽.° 提交于 2019-12-06 08:26:16

First off please note your problem is not related to JXTable but renderers / editors / model.

As @mKorbel points out JCheckBox is the default Renderer/Editor for booleans and generally speaking you won't need to re-invent the wheel: just override getColumnClass() properly to return Boolean on both 5th and 6th columns.

However, because of this requirement:

If the first checkbox is unchecked, the second must be disabled and unchecked.

This is not the default renderer's behavior so you actually need your own renderer. But only renderer, you don't need an editor: as @mKorbel points out you need a little work with the table model.

Renderer

class CheckBoxCellRenderer implements TableCellRenderer {

    private final JCheckBox renderer;

    public CheckBoxCellRenderer() {
        renderer = new JCheckBox();
        renderer.setHorizontalAlignment(SwingConstants.CENTER);
    }

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

        Color bg = isSelected 
                ? table.getSelectionBackground() : table.getBackground();

        renderer.setBackground(bg);
        renderer.setEnabled(table.isCellEditable(row, column));
        renderer.setSelected(value != null && (Boolean)value);
        return renderer;
    }
}

Model

You need to work on both isCellEditable() and setValueAt() methods to properly update your second booleans column based on values on first one. For instance consider this snippet:

// A default model with 5 rows and 6 columns
DefaultTableModel model = new DefaultTableModel(5, 6) {
    @Override
    public Class<?> getColumnClass(int columnIndex) {
        switch(columnIndex) {
            case 4:
            case 5: return Boolean.class; // Both 5th and 6th columns are booleans
        }
        return super.getColumnClass(columnIndex);
    }

    @Override
    public boolean isCellEditable(int row, int column) {
        /*
         * In order to know if 6th column is editable, you have to check
         * 5th column's value.
         */
        if(column == 5) {
            Object value = getValueAt(row, 4);
            return value != null && (Boolean)value;
        }
        return super.isCellEditable(row, column);
    }

    @Override
    public void setValueAt(Object aValue, int row, int column) {
        /*
         * If 5th column value is updated to FALSE, you need to 
         * set 6th column's value to FALSE as well
         */
        if(column == 4) {
            super.setValueAt(Boolean.FALSE, row, 5);
        } 
        super.setValueAt(aValue, row, column);
    }
};

Test it

Here is a complete test case. Hope it helps.

import java.awt.Color;
import java.awt.Component;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;

/**
 * @author dic19
 */
public class Demo {

    private void createAndShowGui() {

        DefaultTableModel model = new DefaultTableModel(5, 6) {
            @Override
            public Class<?> getColumnClass(int columnIndex) {
                switch(columnIndex) {
                    case 4:
                    case 5: return Boolean.class;
                }
                return super.getColumnClass(columnIndex);
            }

            @Override
            public boolean isCellEditable(int row, int column) {
                if(column == 5) {
                    Object value = getValueAt(row, 4);
                    return value != null && (Boolean)value;
                }
                return super.isCellEditable(row, column);
            }

            @Override
            public void setValueAt(Object aValue, int row, int column) {
                if(column == 4) {
                    super.setValueAt(false, row, 5);
                } 
                super.setValueAt(aValue, row, column);
            }
        };

        JTable table = new JTable(model);
        table.getDefaultRenderer(null);
        table.getColumnModel().getColumn(5).setCellRenderer(new CheckBoxCellRenderer());

        JScrollPane scrollPane = new JScrollPane(table);

        JFrame frame = new JFrame("Demo");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(scrollPane);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    class CheckBoxCellRenderer implements TableCellRenderer {

        private final JCheckBox renderer;

        public CheckBoxCellRenderer() {
            renderer = new JCheckBox();
            renderer.setHorizontalAlignment(SwingConstants.CENTER);
        }

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

            Color bg = isSelected 
                    ? table.getSelectionBackground() : table.getBackground();

            renderer.setBackground(bg);
            renderer.setEnabled(table.isCellEditable(row, column));
            renderer.setSelected(value != null && (Boolean)value);
            return renderer;
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Demo().createAndShowGui();
            }
        });
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!