Change the background color of a row in a JTable
Asked Answered
F

5

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?

Fontenot answered 6/10, 2010 at 18:15 Comment(0)
B
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);
Bushwhack answered 6/10, 2010 at 18:41 Comment(1)
why model should know about the colors? is that an mvc breaking?Elijaheliminate
G
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;
    }
});
Garcon answered 19/7, 2012 at 9:53 Comment(5)
You are right, This is working but why this only works for first 5 columns? any idea?Clevey
@Sahan because beyond 5th column there might be a custom cell-renderer.Universally
i tried this olivier, but after i used that code above the effect is that i unable to use .setSelectionBackground(Color.yellow); any longer.... :(Curch
@Curch you can set the selection color in the renderer as well by using the provided isSelected argumentBiramous
this works right but I have also set entire row selection enabled for JTable. Looking for a solution working correctly with JTable.setRowSelectionAllowed(true);Chapfallen
B
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);
Bushwhack answered 6/10, 2010 at 18:41 Comment(1)
why model should know about the colors? is that an mvc breaking?Elijaheliminate
O
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;
    }
};
Overplus answered 7/10, 2010 at 2:33 Comment(2)
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! :)Carpology
I like the idea that you can replace cell renderers and still have consistent row coloring.Grenoble
H
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));
    }
}
Heall answered 6/10, 2010 at 18:33 Comment(0)
T
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.

Tva answered 6/10, 2010 at 18:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.