24

I have a JTable with 3 columns. I've set the TableCellRenderer for all the 3 columns like this (maybe not very effective?).

 for (int i = 0; i < 3; i++) {
     myJTable.getColumnModel().getColumn(i).setCellRenderer(renderer);
 }

The getTableCellRendererComponent() returns a Component with a random background color for each row.
How could I change the background to an other random color while the program is running?

user
  • 6,567
  • 18
  • 58
  • 85

5 Answers5

31

Resumee of Richard Fearn's answer , to make each second line gray:

jTable.setDefaultRenderer(Object.class, new DefaultTableCellRenderer()
{
    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
    {
        final Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
        c.setBackground(row % 2 == 0 ? Color.LIGHT_GRAY : Color.WHITE);
        return c;
    }
});
Olivier Faucheux
  • 2,520
  • 3
  • 29
  • 37
  • You are right, This is working but why this only works for first 5 columns? any idea? – Disapamok Aug 16 '16 at 09:50
  • @Sahan because beyond 5th column there might be a custom cell-renderer. – Enkuushka Feb 13 '17 at 07:29
  • i tried this olivier, but after i used that code above the effect is that i unable to use .setSelectionBackground(Color.yellow); any longer.... :( – gumuruh Nov 15 '17 at 09:43
  • @gumuruh you can set the selection color in the renderer as well by using the provided isSelected argument – User892313 Jul 04 '18 at 12:44
  • this works right but I have also set entire row selection enabled for JTable. Looking for a solution working correctly with JTable.setRowSelectionAllowed(true); – Pekmezli Dürüm Aug 30 '23 at 09:02
24

One way would be store the current colour for each row within the model. Here's a simple model that is fixed at 3 columns and 3 rows:

static class MyTableModel extends DefaultTableModel {

    List<Color> rowColours = Arrays.asList(
        Color.RED,
        Color.GREEN,
        Color.CYAN
    );

    public void setRowColour(int row, Color c) {
        rowColours.set(row, c);
        fireTableRowsUpdated(row, row);
    }

    public Color getRowColour(int row) {
        return rowColours.get(row);
    }

    @Override
    public int getRowCount() {
        return 3;
    }

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

    @Override
    public Object getValueAt(int row, int column) {
        return String.format("%d %d", row, column);
    }
}

Note that setRowColour calls fireTableRowsUpdated; this will cause just that row of the table to be updated.

The renderer can get the model from the table:

static class MyTableCellRenderer extends DefaultTableCellRenderer {

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        MyTableModel model = (MyTableModel) table.getModel();
        Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
        c.setBackground(model.getRowColour(row));
        return c;
    }
}

Changing a row's colour would be as simple as:

model.setRowColour(1, Color.YELLOW);
Richard Fearn
  • 25,073
  • 7
  • 56
  • 55
16

The other answers given here work well since you use the same renderer in every column.

However, I tend to believe that generally when using a JTable you will have different types of data in each columm and therefore you won't be using the same renderer for each column. In these cases you may find the Table Row Rendering approach helpfull.

In essence it suggests to override JTable's prepareRenderer method.

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

        //  add custom rendering here

        return c;
    }
};
Queeg
  • 7,748
  • 1
  • 16
  • 42
camickr
  • 321,443
  • 19
  • 166
  • 288
  • 1
    I agree. It seemed to me that `TableModel` is supposed to hold table data. Rendering should be performed somewhere else. The linked article is enlightening, thank! :) – Matthieu Jul 26 '13 at 11:28
  • I like the idea that you can replace cell renderers and still have consistent row coloring. – Queeg Jul 22 '23 at 09:55
1

This is basically as simple as repainting the table. I haven't found a way to selectively repaint just one row/column/cell however.

In this example, clicking on the button changes the background color for a row and then calls repaint.

public class TableTest {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final Color[] rowColors = new Color[] {
                randomColor(), randomColor(), randomColor()
        };
        final JTable table = new JTable(3, 3);
        table.setDefaultRenderer(Object.class, new TableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table,
                    Object value, boolean isSelected, boolean hasFocus,
                    int row, int column) {
                JPanel pane = new JPanel();
                pane.setBackground(rowColors[row]);
                return pane;
            }
        });
        frame.setLayout(new BorderLayout());

        JButton btn = new JButton("Change row2's color");
        btn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                rowColors[1] = randomColor();
                table.repaint();
            }
        });

        frame.add(table, BorderLayout.NORTH);
        frame.add(btn, BorderLayout.SOUTH);
        frame.pack();
        frame.setVisible(true);
    }

    private static Color randomColor() {
        Random rnd = new Random();
        return new Color(rnd.nextInt(256),
                rnd.nextInt(256), rnd.nextInt(256));
    }
}
Mark Peters
  • 80,126
  • 17
  • 159
  • 190
1

The call to getTableCellRendererComponent(...) includes the value of the cell for which a renderer is sought.

You can use that value to compute a color. If you're also using an AbstractTableModel, you can provide a value of arbitrary type to your renderer.

Once you have a color, you can setBackground() on the component that you're returning.

Andy Thomas
  • 84,978
  • 11
  • 107
  • 151