1

So say that we have a JTable with 31 columns and 10 rows. And I want to change the color of the 2 Column 4 row to red. And after I do that change another cell color without loosing the color of my previous cell.

I have tried the following without success:

public class CellR extends DefaultTableCellRenderer {

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

        setForeground(Color.white);
        if(row == TestHotel.v.getRow()  && column == TestHotel.v.getCol()){
            // Only for specific cell
            // c.setFont(/* special font*/);
            // you may want to address isSelected here too
            setForeground(Color.BLACK);
            setBackground(Color.RED);
         } 
         return this;
}

If I call the renderer the first time it is working... But if I then want to change another cell color I am loosing the first one.

Robby Cornelissen
  • 91,784
  • 22
  • 134
  • 156
uses134
  • 25
  • 6
  • This isn't nearly enough information to debug your problem. Please provide an [MCVE](http://stackoverflow.com/help/mcve). – Kevin Workman Jul 03 '14 at 13:42
  • 2
    agree with SSCCE/MCVE, short, runnable, compilable, with hardcoded value for JTable/XxxTableModel in local variable, because looks like as `if(row == TestHotel.v.getRow() && column == TestHotel.v.getCol()){` returns number of stars in the Milky Way – mKorbel Jul 03 '14 at 13:47
  • note code in this form could be works for JTables view that isn't sorted or filtered – mKorbel Jul 03 '14 at 13:48
  • The table is repainted every time when some modification occurs. Then you need to save all the cells you want to change the color. – elias Jul 03 '14 at 13:53

2 Answers2

2

The cell renderers in tables and lists are used like a "stamp". One component is used for painting all the cells. Also see Concepts: Editors and Renderers. If you want to retain the information about the "highlighted" cells, you somehow have to store them.

An example (extended based on the comments) :

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

public class CellRendererTest
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI()
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        String[] columnNames = {
            "First Name", "Last Name", "Sport" };
        Object[][] data = {
            {"Kathy", "Smith", "Snowboarding" },
            {"John", "Doe", "Rowing" },
            {"Sue", "Black", "Knitting"},
            {"Jane", "White", "Speed reading"},
            {"Joe", "Brown", "Pool"}
        };
        final JTable table = new JTable(data, columnNames);

        final ColoringCellRenderer cellRenderer = new ColoringCellRenderer(); 
        TableColumnModel columnModel = table.getColumnModel();
        int cc = columnModel.getColumnCount();
        for (int c=0; c<cc; c++)
        {
            TableColumn column = columnModel.getColumn(c);
            column.setCellRenderer(cellRenderer);
        }
        JScrollPane scrollPane = new JScrollPane(table);
        f.getContentPane().setLayout(new BorderLayout());
        f.getContentPane().add(scrollPane, BorderLayout.CENTER);

        JButton addRandomColorButton = new JButton("Add random color");
        addRandomColorButton.addActionListener(new ActionListener()
        {
            private Random random = new Random(0);
            @Override
            public void actionPerformed(ActionEvent e)
            {
                int rows = table.getRowCount();
                int cols = table.getColumnCount();
                int row = random.nextInt(rows);
                int col = random.nextInt(cols);
                int r = random.nextInt(255);
                int g = random.nextInt(255);
                int b = random.nextInt(255);
                cellRenderer.setCellColor(row, col, new Color(r,g,b));
                table.repaint();
            }
        });
        f.getContentPane().add(addRandomColorButton, BorderLayout.SOUTH);

        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}


class ColoringCellRenderer extends DefaultTableCellRenderer
{
    private final Map<Point, Color> cellColors = new HashMap<Point, Color>();

    void setCellColor(int r, int c, Color color)
    {
        if (color == null)
        {
            cellColors.remove(new Point(r,c));
        }
        else
        {
            cellColors.put(new Point(r,c), color);
        }
    }

    private Color getCellColor(int r, int c)
    {
        Color color = cellColors.get(new Point(r,c));
        if (color == null)
        {
            return Color.WHITE;
        }
        return color;
    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value,
        boolean isSelected, boolean hasFocus, int row, int column)
    {
        super.getTableCellRendererComponent(
            table, value, isSelected, hasFocus, row, column);
        Color color = getCellColor(row, column);
        setBackground(color);
        return this;
    }
}

EDIT: The remaining part was from the original answer, using only a single cell color. The new one above is more complete (and more powerful, because it can emulate the single-color renderer), but I'll leave this here for completeness

This could be achieved with a renderer like this one:

class ColoringCellRenderer extends DefaultTableCellRenderer
{
    private final Set<Point> highlightedCells = new HashSet<Point>();

    void setHighlighted(int r, int c, boolean highlighted)
    {
        if (highlighted)
        {
            highlightedCells.add(new Point(r,c));
        }
        else
        {
            highlightedCells.remove(new Point(r,c));
        }
    }

    private boolean isHighlighted(int r, int c)
    {
        return highlightedCells.contains(new Point(r,c));
    }

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

        if (isHighlighted(row,  column))
        {
            setForeground(Color.BLACK);
            setBackground(Color.RED);
        }
        else
        {
            setForeground(Color.BLACK);
            setBackground(Color.WHITE);
        }
        return this;
    }
}

You can then create an instance of this renderer, and add or remove cells to be highlighted:

ColoringCellRenderer r = new ColoringCellRenderer();
// Assign renderer to table...
...

// Later, highlight cells:
r.setHighlighted(4,2,true);
r.setHighlighted(6,1,true);
r.setHighlighted(1,5,false);
...

If you want different colors for the cells, you could replace the Set with a Map that maps a particular Point (representing the row/column of the cell) to a Color object.

Marco13
  • 53,703
  • 9
  • 80
  • 159
  • Thank you..This was exactly what i was wanted..:) Can you give a litle bit more info about how i can make it with 2 colors...(i am a begginer in this) – uses134 Jul 03 '14 at 14:44
  • @user3801896 I extended the answer accordingly – Marco13 Jul 03 '14 at 15:13
  • @Marco13 disagree (`JTable table, Object value, boolean isSelected, boolean hasFocus, ` **int row**, **int column**) too much effort, simple to use prepareRenderer, note by test, changes to JTables view should be, must be wrapped into if (table.getRowCount > 0) – mKorbel Jul 04 '14 at 10:45
  • @mKorbel Not entirely sure what you mean. One can override this method, but the cell->color mapping has to be stored somewhere (and I prefer using a renderer over subclassing JTable, but that may be a detail here...) – Marco13 Jul 04 '14 at 11:37
  • @Marco13 `I want to change the color of the 2 Column 4 row to red.` ---> is exactly job for parameters int row, int column (paramaters from XxxRenderer) only, not neccessary to test, hold, create anything else, any my view is usage of [prepareRenderer exclusivelly](http://stackoverflow.com/a/9737299/714968), just about to test row and column coordinates only, nor convert view to model – mKorbel Jul 04 '14 at 11:52
  • @Marco13 prepareRenderer isn't familair with empty XxxTableModel, then my point to test if number of rows is greater than zero – mKorbel Jul 04 '14 at 11:54
  • @mKorbel Still not sure what you mean. He wants to assign different colors to different cells (as in the first comment to this answer). But maybe you'd like to propose a different solution as an answer. – Marco13 Jul 04 '14 at 13:29
0

You need to set the cell renderer on the column that you want it on.

If you say that you want cell color of row 2 column 4 to be red, then you should set the renderer on the 4th column. You could even set the renderer on all columns.

Then all you have to do is do an if-check on the row. ie. if (row == 4). But I assume you would get your values from your TestHotel.v object instead.

Oliver Watkins
  • 12,575
  • 33
  • 119
  • 225
  • But if i set in in specific column lets say number 2 and the first time i change the cell in the row 10. If the next time i want to change the 11 row in the 2 column i will loose the previous edit...i think.. – uses134 Jul 03 '14 at 14:00
  • you just need to update the table updateUI(), and it should respect any changes to the model. If the values in your TestHotl.v have changed then you should see those changes. – Oliver Watkins Jul 03 '14 at 14:14