I know there are previous topics for a similar problem but even with it I wasn't able to resolve my problem.
So the thing is, when I add a new empty row to my JTable I want to highlight it in gray. So it works for the first one but when I try to add a second row, the second will be white...
I tried to debbug but without success, I didn't find my mistake.
Here is the class to highlight a row :
class GrayWhiteRenderer extends DefaultTableCellRenderer {
private int rowToColored;
GrayWhiteRenderer(int rowToColored) {
this.rowToColored = rowToColored;
Color color = UIManager.getColor ( "table.row" );
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (UIManager.getColor ( "table.row" )==Color.GRAY) {
c.setBackground(Color.GRAY.brighter());
}
else if(row == rowToColored) {
c.setBackground(Color.GRAY.brighter());
} else {
c.setBackground(Color.WHITE);
}
return c;
}
}
I store the index of all new row in rowToAdd at the begining of it (for exemple : [19, 20, 21, -1, -1, ...]. -1 is to know when I have to stop looking if I have to highlight more) :
while(rowToAdd[k]!=-1) {
System.out.println("rowToAdd[k] : "+rowToAdd[k]);
dataTable.setDefaultRenderer(Object.class, new GrayWhiteRenderer(rowToAdd[k]));
k++;
}
And here is a class to test it :
package Graphic;
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
class Test implements Runnable, ActionListener {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Test());
}
JTable table;
#Override
public void run() {
JFrame frame = new JFrame("Custom Cell Renderer");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
table = new JTable(new DefaultTableModel(0, 2) {
#Override
public Class<?> getColumnClass(int c) {
return Object.class;
}
});
class GrayWhiteRenderer extends DefaultTableCellRenderer {
private int rowToColored;
GrayWhiteRenderer(int rowToColored) {
this.rowToColored = rowToColored;
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (UIManager.getColor ( "table.row" )==Color.GRAY) {
c.setBackground(Color.GRAY.brighter());
}
else if(row == rowToColored) {
c.setBackground(Color.GRAY.brighter());
} else {
c.setBackground(Color.WHITE);
}
return c;
}
}
table.setDefaultRenderer(Object.class, new GrayWhiteRenderer(table.getRowCount()));
table.setTableHeader(null);
JButton btn = new JButton("Add Row");
btn.addActionListener(this);
JToolBar bar = new JToolBar();
bar.setFloatable(false);
bar.add(btn);
JPanel content = new JPanel(new BorderLayout());
content.add(bar, BorderLayout.NORTH);
content.add(new JScrollPane(table), BorderLayout.CENTER);
frame.setContentPane(content);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent ae) {
int nextRow = table.getRowCount();
DefaultTableModel model = (DefaultTableModel)table.getModel();
model.addRow(new Object[] { "" + nextRow, "" + nextRow });
for(int i=0; i<model.getColumnCount(); i++) {
table.setDefaultRenderer(Object.class, new GrayWhiteRenderer(i));
}
}
}
So, I've fixed your example. Here is your code with my comments
#Override
public void actionPerformed(ActionEvent ae) {
int nextRow = table.getRowCount();
DefaultTableModel model = (DefaultTableModel) table.getModel();
model.addRow(new Object[] {"" + nextRow, "" + nextRow});
// the correct row is: nextRow. No loop required here.
table.setDefaultRenderer(Object.class, new GrayWhiteRenderer(nextRow));
}
I would also correct your renderer to provide selection highlight
class GrayWhiteRenderer extends DefaultTableCellRenderer {
private int rowToColored;
GrayWhiteRenderer(int rowToColored) {
this.rowToColored = rowToColored;
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
// As I know there is no value is registered for "table.row" in UIManager
// so I've skipped the first condition
if (row == rowToColored) {
c.setBackground(Color.GRAY.brighter());
} else {
// use correct color depended on whether the cell is selected or not!
c.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
}
return c;
}
}
Related
When I click on a table cell, and then click on a second table cell, a number of mouse and focus events occur that I do not understand. For example, clicking of cell (1, 0) and then on cell (2, 1) and then the Done button to display the sequence of events causes the following events:
1) Mouse Pressed on cell (1,0)
2) Focus Gained on cell (1,0)
3) Mouse Pressed on cell (1,0) - why(?)
4) Mouse Pressed on cell (2,1)
5) Focus Lost on cell (1,0) - why(?)
6) Focus Lost on cell (2,1)
7) Focus Gained on cell (1,0) - why(?)
8) Focus Gained on cell (2,1) - why(?)
9) Focus Lost on cell (1,0) - why(?)
10) Focus lost on cell (2,1) - why(?)
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.*;
import static javax.swing.SwingConstants.CENTER;
import static javax.swing.SwingConstants.LEFT;
import javax.swing.SwingUtilities;
import javax.swing.table.*;
public class TestFocus {
public ArrayList<String> mylog;
public int number = 0;
public TestFocus() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = createPanel();
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public JPanel createPanel() {
mylog = new ArrayList<>();
JPanel panel = new JPanel();
TestTableModel tm = new TestTableModel();
JLabel title = new JLabel("Test Table");
JTable table = new JTable(tm);
TableColumnModel tcm = table.getColumnModel();
TestTableCellEditor editor = new TestTableCellEditor();
TestTableCellRenderer renderer = new TestTableCellRenderer();
for (int i = 0; i < tm.getColumnCount(); i++) {
TableColumn column = tcm.getColumn(i);
column.setCellEditor(editor);
column.setCellRenderer(renderer);
}
JScrollPane jsp = new JScrollPane(table);
JButton btn = new JButton("Done");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
for (String s : mylog) {
System.out.println(s);
}
}
});
panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
panel.add(jsp);
panel.add(btn);
return panel;
}
class TestTableModel extends AbstractTableModel {
private String[] columnNames = { "Firstname", "Lastname", "Age" };
private Object[][] data = {
{ "John", "Smith", 29},
{ "Mary", "Thomas", 63},
{ "Peter", "Jones", 48} };
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return data.length;
}
public String getColumnName(int col) {
return columnNames[col];
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
public Class getColumnClass(int col) {
return getValueAt(0, col).getClass();
}
public String getColumnClassName(int col) {
if (col == 2) {
return "Integer";
} else {
return "String";
}
}
public boolean isCellEditable(int row, int col) {
return true;
}
public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
fireTableCellUpdated(row, col);
}
}
public class TestTableCellEditor extends AbstractCellEditor
implements TableCellEditor {
JComponent component = new JTextField();
#Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
((JTextField)component).addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent me) {
mylog.add(++number + ") Mouse pressed: " +
value.toString() + ": r/c ("+row+"/"+column+")");
}
});
((JTextField)component).addFocusListener(new FocusListener() {
#Override
public void focusGained(FocusEvent fe) {
mylog.add(++number + ") Focus gained: " +
value.toString() + ": r/c ("+row+"/"+column+")");
}
#Override
public void focusLost(FocusEvent fe) {
mylog.add(++number + ") FocusLost: " +
value.toString() + ": r/c ("+row+"/"+column+")");
}
});
if (value != null) {
((JTextField)component).setText(value.toString());
} else {
((JTextField)component).setText("");
}
return (JTextField)component;
}
#Override
public Object getCellEditorValue() {
return ((JTextField)component).getText();
}
}
public class TestTableCellRenderer extends JLabel implements
TableCellRenderer {
public TestTableCellRenderer() {
this.setOpaque(true);
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, final int row, int column) {
DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
Component c = renderer.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, column);
if (hasFocus) {
c.setBackground(Color.yellow);
}
TestTableModel tm = (TestTableModel)table.getModel();
int col = table.convertColumnIndexToModel(column);
String colname = tm.getColumnName(col);
String type = tm.getColumnClassName(col);
if (type.equals("Integer") || type.equals("Int")) {
((JLabel)c).setHorizontalAlignment(CENTER);
} else { // add padding
((JLabel)c).setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));
((JLabel)c).setHorizontalAlignment(LEFT);
}
if (type.equals("String")) {
String text = ((JLabel)c).getText();
((JLabel)c).setToolTipText(text);
}
return c;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TestFocus();
}
});
}
}
getTableCellEditorComponent method will be called very time the JTable gets rendered - a lot of times. Inside it you textfield.addMouseListener(). That means the listener will be added a lot of times. That's why you get many events instead of one (all these listeners are notified). In order to solve it, add the listeners only one time. You can add the listeners in constructor of this class.
For example:
public class TestTableCellEditor extends AbstractCellEditor implements TableCellEditor {
private JTextField component;
public TestTableCellEditor() {
component = new JTextField();
component.addMouseListener(mouseListener);
component.addFocusListener(focusListener)
}
#Override
public Object getCellEditorValue() {
return component.getText();
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
component.setText(value == null ? "" : String.valueOf(value));
return component;
}
}
I want to change the format of column 2 (Columna 2) to currency format of all the data, I am trying with this, but it does not do anything.
Could you help me?
These are my data:
I want the data to come out like this:
With this code I am trying:
public class CurrencyCellRenderer extends DefaultTableCellRenderer {
#Override
public final Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
final Component result = super.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, column);
if (value instanceof Number) {
setHorizontalAlignment(JLabel.CENTER);
setText(defaultFormat.format(value));
} else {
setText("NO");
}
return result;
}
}
jTable1.getColumnModel().getColumn(2).setCellRenderer(new CurrencyCellRenderer());
It does not do anything, could you help me?
Thanks!!!
You need to create result after changing value's value. Creating result before, will just return the same old data.
e.g.,
private class CurrencyCellRenderer extends DefaultTableCellRenderer {
#Override
public final Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (value == null) {
value = 0.0;
}
value = myFormat.format(value);
final Component result = super.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, column);
return result;
}
}
My MCVE for proof of concept:
import java.awt.BorderLayout;
import java.awt.Component;
import java.text.NumberFormat;
import java.util.Locale;
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
#SuppressWarnings("serial")
public class CurrencyTable extends JPanel {
private static final String[] TABLE_HEADERS = { "Text", "Value" };
private static final Object[][] DATA = { { "Foo", 1.1 }, { "Bar", 2.2 }, { "Bax", 3.3 } };
private DefaultTableModel tableModel = new DefaultTableModel(DATA, TABLE_HEADERS);
private JTable table = new JTable(tableModel);
private NumberFormat myFormat = NumberFormat.getCurrencyInstance(Locale.FRANCE);
public CurrencyTable() {
table.getColumnModel().getColumn(1).setCellRenderer(new CurrencyCellRenderer());
setLayout(new BorderLayout());
add(new JScrollPane(table));
}
private class CurrencyCellRenderer extends DefaultTableCellRenderer {
#Override
public final Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (value == null) {
value = 0.0;
}
value = myFormat.format(value);
final Component result = super.getTableCellRendererComponent(table, value, isSelected,
hasFocus, row, column);
return result;
}
}
private static void createAndShowGui() {
CurrencyTable mainPanel = new CurrencyTable();
JFrame frame = new JFrame("CurrencyTable");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
Ok, i have the solution:
NumberFormat defaultFormat = NumberFormat.getCurrencyInstance();
public class MyRenderer extends JLabel implements TableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int col) {
DefaultTableCellRenderer renderer
= new DefaultTableCellRenderer();
Component c = renderer.getTableCellRendererComponent(table,
value, isSelected, hasFocus, row, col);
String s = "";
if (col == 2) {
double d = Double.parseDouble( String.valueOf(value)) ;
s = defaultFormat.format(d);
c = renderer.getTableCellRendererComponent(table, s,
isSelected, hasFocus, row, col);
((JLabel) c).setHorizontalAlignment(SwingConstants.RIGHT);
}
return c;
}
}
jTable1.getColumnModel().getColumn(2).setCellRenderer(new MyRenderer());
Image here
Thanks for all guys!
I tried to find here for a long time answer for my question but without the exact result i expected.
I have JTable which every time i am changing values in entire column (only in one column every time).
I want to listen to a table changes and when data changes in the column, the color in the column will be changed too and all other columns will be in the default color.
This is the code for the table listener:
Class CustomCellRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component rendererComp = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
table.getModel().addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
if(***here i want to know which column changed or something like that***){
rendererComp.setBackground(Color.CYAN);
}
}
});
return rendererComp ;
}
}
and this is the code for the table creation:
private void createTable() {
tablePanel.setLayout(new FlowLayout(FlowLayout.LEFT));
DefaultTableModel tableModel = new DefaultTableModel(){
#Override
public boolean isCellEditable(int row, int column) {
//all cells false
return false;
}
};
contentTable = new JTable(tableModel);
contentTable.setGridColor(Color.LIGHT_GRAY);
for(int i=0; i<columnSize; i++) {
tableModel.addColumn("0");
}
for(int i=0; i<rawSize; i++) {
tableModel.addRow(new Object[] { "" });
}
for(int i=0; i<rawSize; i++) {
for(int j=0; j<tableModel.getRowCount(); j++) {
tableModel.setValueAt("0", j, i);
}
}
for(int i=0; i<ramSize; i++) {
contentTable.getColumnModel().getColumn(i).setCellRenderer(new CustomCellRenderer());
}
JScrollPane scrollPane = new JScrollPane(contentTable);
scrollPane.setPreferredSize(new Dimension(400, 150));
tablePanel.add(scrollPane);
}
Store the desired state in the TableModel; let the TableCellRenderer use the state to condition the view accordingly. In the example below, as soon as setValueAt() updates any cell, edited is marked true. The render, which is applied to column zero, changes the display accordingly. Note how clearEdited() invokes fireTableDataChanged() to force the table to render all cells when called in the Clear handler.
Addendum: The update below shows one approach to handling multiple columns independently. The CustomModel now contains a Map<Integer, Boolean> to store the edited state for each column to which the CustomRenderer is applied. As an aside, the CustomRenderer now invokes convertColumnIndexToModel() and sets the selection color correctly.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.util.HashMap;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
/**
* #see http://stackoverflow.com/a/37439731/230513
*/
public class Test {
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CustomModel model = new CustomModel();
model.setColumnIdentifiers(new String[]{"A", "B"});
for (int i = 0; i < 16; i++) {
model.addRow(new String[]{"A:" + i, "B:" + i});
}
JTable table = new JTable(model) {
#Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(100, getRowHeight() * getRowCount() / 2);
}
};
table.getColumnModel().getColumn(0).setCellRenderer(new CustomRenderer(model));
table.getColumnModel().getColumn(1).setCellRenderer(new CustomRenderer(model));
f.add(new JScrollPane(table));
JPanel p = new JPanel();
p.add(new JButton(new UpdateAction("Update A", model, 0)));
p.add(new JButton(new UpdateAction("Update B", model, 1)));
p.add(new JButton(new AbstractAction("Clear") {
#Override
public void actionPerformed(ActionEvent e) {
model.clearEdited(0);
model.clearEdited(1);
}
}));
f.add(p, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static class CustomModel extends DefaultTableModel {
private final Map<Integer, Boolean> edited = new HashMap<>();
public boolean isEdited(int column) {
return edited.get(column) != null && edited.get(column);
}
public void clearEdited(int column) {
edited.put(column, false);
fireTableDataChanged();
}
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
#Override
public void setValueAt(Object aValue, int row, int column) {
super.setValueAt(aValue, row, column);
edited.put(column, true);
}
}
private static class CustomRenderer extends DefaultTableCellRenderer {
private final CustomModel model;
public CustomRenderer(CustomModel model) {
this.model = model;
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int col) {
Component c = super.getTableCellRendererComponent(
table, value, isSelected, hasFocus, row, col);
if (model.isEdited(table.convertColumnIndexToModel(col))) {
c.setBackground(Color.cyan);
} else if (isSelected) {
c.setBackground(table.getSelectionBackground());
} else {
c.setBackground(table.getBackground());
}
return c;
}
}
private static class UpdateAction extends AbstractAction {
private final CustomModel model;
private final int column;
public UpdateAction(String name, CustomModel model, int column) {
super(name);
this.model = model;
this.column = column;
}
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < model.getRowCount(); i++) {
model.setValueAt(model.getValueAt(i, column), i, column);
}
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Test()::display);
}
}
I searched for tutorials for adding button in jtable and found a class file from, http://tips4java.wordpress.com/2009/07/12/table-button-column/ Where to set label for the button?
[code]
private void createTable(){
model = new DefaultTableModel();
editorTable.setModel(model);
model.addColumn("COL1");
model.addColumn("COL2");
model.addColumn("ADD");
model.addColumn("DELETE");
model.addRow(new Object[]{"DATA1", "DATA2"});
Action delete = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
editorTable = (JTable) e.getSource();
int modelRow = Integer.valueOf(e.getActionCommand());
((DefaultTableModel) editorTable.getModel()).removeRow(modelRow);
}
};
ButtonColumn bc = new ButtonColumn(editorTable, delete, 3);
bc.setMnemonic(KeyEvent.VK_D);
}
[/code]
It is set automatically in the table renderer and editor from the data in your DefaultTableModel. For example, for the table editor, the code is:
public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column) {
...
editButton.setText( value.toString() );
editButton.setIcon( null );
...
}
where value is the value from your table model. See ButtonColumn.java for details.
EDIT: Since you are adding 4 columns, you should probably change your row data to
model.addRow(new Object[]{"DATA1", "DATA2", "DATA3", "DELETE"});
in order to see the delete buttons on the 4th column.
MyClass myClass = new MyClass();
jTable1.getColumnModel().getColumn(0).setCellEditor(myClass);
jTable1.getColumnModel().getColumn(0).setCellRenderer(myClass);
class MyClass extends AbstractCellEditor implements TableCellEditor, TableCellRenderer
{
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)
{
JPanel panel=(JPanel)jTable1.getCellRenderer(row, column).getTableCellRendererComponent(table, value, isSelected, isSelected, row, column);
panel.setBackground(table.getSelectionBackground());
return panel;
}
#Override
public Object getCellEditorValue()
{
return null;
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
AbstractAction action = new AbstractAction()
{
#Override
public void actionPerformed(ActionEvent e)
{
JOptionPane.showMessageDialog(rootPane,"Row :"+jTable1.getSelectedRow()+" "+ e.getActionCommand() + " clicked");
}
};
JButton button1 = new JButton(action);
JButton button2 = new JButton(action);
button1.setText("Button1");
button2.setText("Button2");
JPanel panel = new JPanel();
panel.add(button1);
panel.add(button2);
panel.setBackground(table.getBackground());
return panel;
}
}
}
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?
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;
}
});
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);
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.
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));
}
}
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.