I am trying to be able to color separate cells in a JTable, but I got only so far to apply a TableCellRenderer on a whole column, which then obviously malfunctions. I have a custom JTable:
public class JColorTable extends JTable{
(...)
public void setCellColor(int col, int row, Color newColor) {
getColumnModel().getColumn(col).setCellRenderer(new ColorField(col, row, newColor, background));
repaint();
}
}
ColorField looks like this:
class ColorField extends DefaultTableCellRenderer {
(...))
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
JLabel l = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (row == newRow && column == newCol) {
l.setBackground(Color.red);
} else {
l.setBackground(defaultColor);
}
return l;
}
}
This works like a charm when I have a single colored cell in a column, but when I try to color another cell in that column, the previous gets deleted (due to the condition in ColorField not applying for the previous column).
Is there a way to only apply ColorField to a single cell, rather than the whole column? If so, how? I did not find anything suitable, I'm afraid.
JTable
has a method getCellRenderer()
that you can override. It is called when a cell needs rendering and returns one based on the row and column.
Your JTable
would need to keep some record of which renderer to use for each cell (by row and column). A 2D array would do it or a Map
with the key being an X,Y value.
Add a method to set the renderer on a particular cell (by row and column) and there you go.
class MyTable extends JTable {
// all the other JTable stuff goes here too ...
public TableCellRenderer getCellRenderer(int row, int column) {
TableCellRenderer myRenderer = getCustomRenderer(row, column);
if (myRenderer != null) {
return myRenderer;
}
// else...
return super.getCellRenderer(row, column);
}
private Map<Integer, Map<Integer, TableCellRenderer>> rendererMap = new ...;
public void setCustomRenderer(int row, int column, TableCellRenderer renderer) {
Map<Integer, TableCellRenderer> m1 = rendererMap.get(row);
if (m1 == null) {
m1 = new ...;
rendererMap.put(row, m1);
}
m1.put(column, renderer);
}
public TableCellRenderer getCustomRenderer(int row, int column) {
Map<Integer, TableCellRenderer> m1 = rendererMap.get(row);
if (m1 == null) {
return null;
}
return m1.get(column);
}
}
The default version of getTableCellRenderer
uses the renderer set on the column if there is one, if not it uses the renderer based on the class of the cell contents. Default cell contents is Object
in many cases. It depends on the TableModel
used.