2
votes

Below is a picture of my JTable. My problem is that the blue background every other row isn't present in the 4th column. My table model and cell renderer are also below.

enter image description here

Table model:

public class MyTableModel extends DefaultTableModel {
    public int getColumnCount() {
        return columnNames.length;
    }

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

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

    public Object getValueAt(int row, int column) {
        return data[row][column];
    }

    public Class getColumnClass(int column) {
        return (getValueAt(0, column).getClass());
    }

    public void setValueAt(Object value, int row, int column) {
        data[row][column] = value;
    }

    public boolean isCellEditable(int row, int column) {
        return (column == 3);
    }
    }

Cell Renderer:

    private class CalendarRenderer extends DefaultTableCellRenderer {
    private static final long serialVersionUID = 1L;

    public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean focused, int row, int column) {
        super.getTableCellRendererComponent(table, value, selected, focused, row, column);

        setBackground(new Color(0xFFFFFF));

        if (row % 2 == 1) {
        setBackground(new Color(0xE8F2FE)); //light blue
        }

        setBorder(null);
        setForeground(Color.black);
        return this;
    }
    }
2
The default editor for Boolean is JCheckBox cell editor, this is actually working correctly. - MadProgrammer
When does Java not work "correctly"? I'm wondering how I can get the fourth column to have a blue background as well. - Joel Christophel
You're going to need to supply your own Boolean TableCellRenderer - MadProgrammer
Your TableModel implementation is confusing. If you are going to extend DefaultTableModel you only need to override the getColumnClass() and isCellEditable() methods. If you are going to override all the methods then you should extend AbstractTableModel. I'm not even sure how your code works since DefaultTableModel uses a Vector to store the data, not a 2-dimensional array, so the code you posted can't be the code you are using. - camickr
It is the code I've been using, and it's been working quite well. - Joel Christophel

2 Answers

8
votes

The "default" cell renderer for Boolean is a check box. If you want to change the way that this cell gets rendered, you're going to have to supply your own TableCellRenderer that implements your own logic.

enter image description here

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;

public class TestTableCellRenderer {

    public static void main(String[] args) {
        new TestTableCellRenderer();
    }

    public TestTableCellRenderer() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JTable table = new JTable();
                table.setModel(new TableModel());
                table.setDefaultRenderer(Boolean.class, new BooleanCellRenderer());

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new JScrollPane(table));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TableModel extends AbstractTableModel {

        private List<Boolean> values = new ArrayList<>(25);

        public TableModel() {
            for (int index = 0; index < 25; index++) {
                values.add((((int) Math.round(Math.random() * 1)) == 0 ? false : true));
            }
        }

        @Override
        public int getRowCount() {
            return values.size();
        }

        @Override
        public int getColumnCount() {
            return 1;
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            return values.get(rowIndex);
        }

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            return Boolean.class;
        }
    }

    public static class BooleanCellRenderer extends JCheckBox implements TableCellRenderer {

        private static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);

        public BooleanCellRenderer() {
            setLayout(new GridBagLayout());
            setMargin(new Insets(0, 0, 0, 0));
            setHorizontalAlignment(JLabel.CENTER);
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            if (value instanceof Boolean) {
                setSelected((Boolean) value);
            }
            if (!isSelected) {
                setBackground(new Color(0xFFFFFF));
                if (row % 2 == 1) {
                    setBackground(new Color(0xE8F2FE)); //light blue
                }
                setForeground(Color.black);
            } else {
                setForeground(table.getSelectionForeground());
                setBackground(table.getSelectionBackground());
            }
            if (hasFocus) {
                setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
            } else {
                setBorder(noFocusBorder);
            }
            return this;
        }
    }
}
3
votes

See Table Row Rendering for a solution that doesn't require you to keep creating custom renderers every time you have columns with different data.

JTable table = new JTable( model )
{
    public Component prepareRenderer(TableCellRenderer renderer, int row, int column)
    {
        Component c = super.prepareRenderer(renderer, row, column);

        //  Alternate row color

        if (!isRowSelected(row))
            c.setBackground(row % 2 == 0 ? getBackground() : Color.LIGHT_GRAY);

        return c;
    }
};