I use TableCellRenderer in a function to change the color of a row.
public void change_color(JTable tableName){
tableName.setDefaultRenderer(Object.class, new TableCellRenderer(){
private DefaultTableCellRenderer DEFAULT_RENDERER = new DefaultTableCellRenderer();
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component c = DEFAULT_RENDERER.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
c.setBackground(Color.RED);
//Add below code here
return c;
}
});
}
It changes the color of entire table. To call this function i use following condition.
if(ellapsed.getMinutes() > 30)
{
change_color(table_dineIn,ellapsed.getMinutes());
}
Cant figure out the problem. I have tried other codes to but nothing helped me.
The cell renderers in JTable, JList etc. are used like a stamp (see Editors and Renderers for details).
This means that usually, the same (identical) JComponent is used for painting all the cells. This component is only filled with the appropriate contents before it is used for painting the cell. And when the background is set to RED, it will remain red until it is set to a different color.
I'm not sure what you wanted to achieve by using this DEFAULT_RENDERER instance. You could simply inherit from DefaultTableCellRenderer and return the component (which is in fact the renderer itself) direcly. However, in any case, you'll have to include some code that makes sure that the appropriate color is set for every call, roughly like
....
if (shouldBeRed(row, column)) {
c.setBackground(Color.RED);
} else {
c.setBackground(notRed);
}
return c;
(note that this can actually be hidden in the call to the super method if you extend DefaultTableCellRenderer, but the details here depend on whether you'll keep this DEFAULT_RENDERER instance or not...)
You might also be interested in this example of blinking table cells, showing how several table cells may be assigned different colors based on certain criteria.
EDIT: An example. Although I usually try to avoid answereing questions like this with examples like this, because even for the slightest modification, you'll ask another question, which in this case will probably in the line of
how to un-highlight the row
how to highlight multiple rows
how to highlight multiple rows with different colors
...
You'll find answers to all these questions in https://stackoverflow.com/a/24556135/3182664 - in the meantime, I'll mark this question as a duplicate.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
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;
public class TableRowColor
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("TableRowColor");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BorderLayout());
final JTable table = createTable();
JScrollPane scrollPane = new JScrollPane(table);
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
JButton changeColorButton = new JButton("Change color");
changeColorButton.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
changeColor(table, 1);
}
});
frame.getContentPane().add(changeColorButton, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private static JTable createTable()
{
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" } };
return new JTable(data, columnNames);
}
public static void changeColor(JTable table, final int coloredRow)
{
table.setDefaultRenderer(Object.class, new DefaultTableCellRenderer()
{
#Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column)
{
super.getTableCellRendererComponent(table, value, isSelected,
hasFocus, row, column);
if (row == coloredRow)
{
setBackground(Color.RED);
}
else
{
setBackground(null);
}
return this;
}
});
table.repaint();
}
}
The following would color 30th row of the table:
public void change_color(JTable tableName){
tableName.setDefaultRenderer(Object.class, new TableCellRenderer(){
private DefaultTableCellRenderer DEFAULT_RENDERER = new DefaultTableCellRenderer();
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component c = DEFAULT_RENDERER.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (row == 30) {
c.setBackground(Color.RED);
}
return c;
}
});
}
Edit:
If you want to choose table color based on data, add that data to the the table model (e.g. a Time stored in particular column), then use the model in the renderer. For example:
static final int TIME_ELLAPSED_COL = ...;
...
if (((Time) table.getModel().getValueAt(row, TIME_ELLAPSED_COL)).getMinutes() > 30) {
c.setBackground(Color.RED);
}
...
Related
I make a timetable with Java, but I cannot solve one problem.
I want to change the foreground color as same as background color or Hiding a value, when some cells have a same value at first detected cell.
Like this...
Here's what I made...
(Sorry about Korean words...)
So, I want to use a DefaultTableCellRenderer, but I can't find a good example about this.
And, I don't know how DefaultTableCellRenderer works. Can't find any explains about that...
So, I want to ask a favor about that problem.
Here's my code:
public class subject_table_renderer extends DefaultTableCellRenderer
{
private Object subject_name = "";
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
Component cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (! isSelected)
{
if(value.equals("")){
cell.setBackground(Color.WHITE);
}
else{
String[] temp = MainFrame.find_list((String)value, MainFrame.subject);
//take a subject_list for decide background color
if(!value.equals(subject_name)){
subject_name = value;
cell.setBackground(get_rand_color(cell, Integer.parseInt(temp[6])));
}
else{
cell.setBackground(get_rand_color(cell, Integer.parseInt(temp[6])));
cell.setForeground(get_rand_color(cell, Integer.parseInt(temp[6])));
}
}
}
return cell;
}
And, I don't know how DefaultTableCellRenderer works. Can't find any explains about that...
Maybe start with the Swing tutorial on Concepts: Editors and Renderers.
You can't use an instance variable to track the previous value because you can't be guaranteed that the rows will always be rendered in sequential order. For example if row 1 is selected and then you click on row 10, only rows 1 and 10 will be repainted.
So the solution is to compare the previous value in the render with code something like:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.table.*;
public class SSCCE extends JPanel
{
public SSCCE()
{
setLayout( new BorderLayout() );
JTable table = new JTable(10, 1);
table.setValueAt("one", 0, 0);
table.setValueAt("one", 1, 0);
table.setValueAt("two", 2, 0);
table.setValueAt("two", 3, 0);
table.setValueAt("two", 4, 0);
table.setValueAt("three", 5, 0);
add( new JScrollPane( table ) );
table.getColumnModel().getColumn(0).setCellRenderer( new DuplicateRenderer() );
}
/*
** Color the focused cell
*/
class DuplicateRenderer extends DefaultTableCellRenderer
{
#Override
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (row > 0 && value != null)
{
Object previous = table.getValueAt(row - 1, column);
if (value.equals(previous))
{
setText("");
}
}
return this;
}
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SSCCE());
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}
I am sorry if the title is not explanatory enough.
I have written a small extension to DefaultTableRenderer class in Java in order to specify cellBackgourd, cellForeground, Alignment and decimal control. I using this class in matlab to control and customise JIDE tables. But have re-created the issue in Java, in order to increase chances of a reply or a possible workaround.
I am successfully able to set cell Background, Foreground, alignment and decimal places as required when the table initialises and displays. However, as soon as I select a row/cell I loose decimal control on displayed data as shown in figure below. Please note that I am using specific cell selection colours, I guess, I am not implementing it properly.
I think, the problem is one of last two lines:
return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
or
return cell;
Java code:
import java.awt.*;
import java.text.DecimalFormat;
import javax.swing.*;
import javax.swing.table.*;
public class DecimalPlacesInTable extends JFrame {
public static void main( String[] args ) {
DecimalPlacesInTable frame = new DecimalPlacesInTable();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.pack();
frame.setVisible( true );
}
public DecimalPlacesInTable() {
Object[] columnNames = { "A", "B", "C" };
Object[][] data = {
{new Double( 850.503 ), new Double( 850.545 ), new Double( 80.54553 ) },
{new Double( 50.52503 ), new Double( 36.4554 ), new Double( 50.41453 ) },
{new Double( 80.544653 ), new Double( 8.3 ), new Double( 80.4553 ) },
{new Double( 50.1553 ), new Double( 246.0943 ), new Double( 50.455 ) }};
JTable table = new JTable(data, columnNames);
// Tell the table what to use to render our column of doubles
for (int i=0; i<3; i++) {
table.getColumnModel().getColumn(i).setCellRenderer(new DecimalFormatRenderer());
getContentPane().add(new JScrollPane(table));
}
}
// Custom Renderer class
static class DecimalFormatRenderer extends DefaultTableCellRenderer
{
public Component getTableCellRendererComponent
(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JComponent cell = (JComponent) super.getTableCellRendererComponent
(table, value, isSelected, hasFocus, row, column);
// set color
cell.setBackground(new Color(0xC8C8C8));
cell.setForeground(new Color(0xFFFFFF));
//set Alignment
((JLabel) cell).setHorizontalAlignment(SwingConstants.CENTER);
//set selection colors
if (isSelected) {
cell.setBackground(new Color(0x3399FF));
cell.setForeground(new Color(0x000000)); // AM
} else {
// set decimals
DecimalFormat DecimalFormatter = new DecimalFormat("#.00");
value = DecimalFormatter.format(value);
return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
}
return cell;
}
}
}
From Concepts: Editors and Renderers - How to Use Tables (The Java? Tutorials > Creating a GUI With JFC/Swing > Using Swing Components)
It is easy to customize the text or image rendered by the default renderer, DefaultTableCellRenderer. You just create a subclass and implement the setValue method so that it invokes setText or setIcon with the appropriate string or image. For example, here is how the default date renderer is implemented:
import java.awt.*;
import java.text.DecimalFormat;
import javax.swing.*;
import javax.swing.table.*;
public class DecimalPlacesInTable2 extends JFrame {
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
DecimalPlacesInTable2 frame = new DecimalPlacesInTable2();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
});
}
public DecimalPlacesInTable2() {
Object[] columnNames = { "A", "B", "C" };
Object[][] data = {
{850.503, 850.545, 80.54553},
{50.52503, 36.4554, 50.41453},
{80.544653, 8.3, 80.4553},
{50.1553, 246.0943, 50.455}
};
//JTable table = new JTable(data, columnNames);
TableModel model = new DefaultTableModel(data, columnNames) {
#Override public Class<?> getColumnClass(int column) {
return Double.class;
}
};
JTable table = new JTable(model);
// Tell the table what to use to render our column of doubles
for (int i = 0; i < 3; i++) {
table.getColumnModel().getColumn(i).setCellRenderer(new DecimalFormatRenderer());
//getContentPane().add(new JScrollPane(table));
}
getContentPane().add(new JScrollPane(table));
}
// Custom Renderer class
static class DecimalFormatRenderer extends DefaultTableCellRenderer {
private final DecimalFormat formatter = new DecimalFormat("#.00");
#Override public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
JLabel cell = (JLabel) super.getTableCellRendererComponent(
table, value, isSelected, hasFocus, row, column);
//set Alignment
cell.setHorizontalAlignment(SwingConstants.CENTER);
//set selection colors
if (isSelected) {
cell.setBackground(new Color(0x3399FF));
cell.setForeground(new Color(0x000000)); // AM
} else {
// set color
cell.setBackground(new Color(0xC8C8C8));
cell.setForeground(new Color(0xFFFFFF));
}
// // set decimals
// if (value instanceof Double) {
// cell.setText(formatter.format(value));
// }
return cell;
}
#Override public void setValue(Object value) {
setText(value instanceof Double ? formatter.format(value) : "");
}
}
}
I've been looking around for a solution to this and I can't make head nor tail from various places of how to get my table to do coloured rows without asking my own question.
From every place I've looked I gather I need to use a cell renderer but the problem is I don't know how to apply it to my own situation.
So I have a simple JTable with 3 columns and I simply want each row to be highlighted in either green, yellow or red depending on the value of a separate variable (not displayed in the table).
It seems like it should be really simple but I can't get how to do it. If it helps my table is defined like:
studentTableModel = new DefaultTableModel(new Object[]{"Name", "StudentNo", "Part"}, 0);
jt_studentTable = new JTable(studentTableModel);
jt_studentTable.getColumnModel().getColumn(2).setPreferredWidth(10);
studentTableModel.addRow(new Object[]{"(empty)", "(empty)", "(empty)"});
JScrollPane jsp_tableScroller = new JScrollPane(jt_studentTable);
jsp_tableScroller.setPreferredSize(new Dimension(200,190));
middleCentrePanel.add(jsp_tableScroller);
The rows in the table change depending of the selection of a combo box.
Thanks in advance.
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
public class RowRendering {
private static Object[] columnName = {"Yes", "No"};
private static Object[][] data = {
{"Y", "N"},
{"N", "Y"},
{"Y", "N"}
};
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
JTable table = new JTable(data, columnName);
table.getColumnModel().getColumn(0).setCellRenderer(new CustomRenderer());
table.getColumnModel().getColumn(1).setCellRenderer(new CustomRenderer());
frame.add(new JScrollPane(table));
frame.setTitle("Rendering in JTable");
frame.pack();
frame.setVisible(true);
}
};
EventQueue.invokeLater(r);
}
}
class CustomRenderer extends DefaultTableCellRenderer
{
private static final long serialVersionUID = 6703872492730589499L;
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
Component cellComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if(row == 0){
cellComponent.setBackground(Color.YELLOW);
} else if ( row == 1){
cellComponent.setBackground(Color.GRAY);
} else {
cellComponent.setBackground(Color.CYAN);
}
return cellComponent;
}
}
I simply want each row to be highlighted in either green, yellow or red depending on the value of a separate variable (not displayed in the table).
Renderers work on data in the table. That is components can only paint themselves when they have all the information needed to do the job.
So somehow you need to add the information to the table. This might be done be adding a 4th column that is hidden. Then the table still has access to the information required.
Then maybe you can use the suggestion in Table Row Renderering.
Maybe this works for you:
class MyCellRenderer extends DefaultTableCellRenderer {
String separatedVariable;
public MyCellRenderer(String separatedVariable) {
this.separatedVariable = separatedVariable;
}
#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);
c.setBackground(Color.WHITE);
c.setForeground(Color.BLACK);
JLabel l = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
if (separatedVariable.equals("YOUR VALUE TO GREEN")) {
l.setBackground(Color.GREEN);
return l;
} else {
if (separatedValue.equals("YOUR VALUE TO YELLOW")) {
l.setBackground(Color.YELLOW);
return l;
} else if (separatedValue.equals("YOUR VALUE TO RED")) {
l.setBaground(Color.RED);
return l;
}
}
return c;
}
}
I just had this same question, but a bit more complicated, since I already had several different renderers for each column, depending on the datatype.
But I found that this works like a charm:
public class MyTable extends JTable {
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component result = super.prepareRenderer(renderer, row, column);
if (mustBeYellow(row, column)) {
result.setBackground(Color.yellow);
}
return result;
}
private boolean mustBeYellow(int row, int column) {
// implement this depending on your data..
return false;
}
}
I have a column in JTable which should display two types: String OR ImageIcon, not both. Each cell in that column has own thread which calculates data. In the beginning I put to each cell an image(like waiting logo), then REPLACE(not append) the image with a string of calculated data. I tried to extend default TableCell renderer, but it displays image like object address(javax.swing.ImageIcon#342...) and then replaces with string. Another variant, it displays the image correctly, but replaces it with empty string(or it is not visible?).
How to set it up so the table displays cell content correctly according to type?
Here is what I have at the moment:
class IconAndStringRenderer extends DefaultTableCellRenderer {
private static final long serialVersionUID = 3606788739290618405L;
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, column);
if (value instanceof Icon) {
setIcon((Icon) value);
setText("");
}
return this;
}
}
Here is JTable:
table = new JTable(model) {
private static final long serialVersionUID = 8058795799817761161L;
public Class<?> getColumnClass(int column) {
if (column == TARGET_COLUMN)
return ImageIcon.class;
else
return super.getColumnClass(column);
}
};
A few more questions:
How to set it so the text replaces the image, not write text after image(even if it's not visible);
How to set text color, I gonna use setForebackground(Color c), but if I use it, the image is not dislayed.
Is it possible to make it working with Jlabel? Set up required Jlabel(with image or text) in the thread which modifies a cell and just setValueAt(label, row, column);
You need a custom renderer which can understand both types you use.
For example
public class IconAndStringRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, column);
if (value instanceof Icon) {
setText("");
setIcon((Icon) value);
}
return this;
}
}
Try to set this class as your column renderer
The default renderer knows how to display both strings and icons. All you have to do is ensure that your TableModel returns the correct class from getColumnClass(), String.class and Icon.class, respectively. Examples may be found here.
Addendum: Here's a minimal example to illustrate the principle, based on default implementations.
Addendum: Not sure if it works when needed to return different classes for the same column.
If you really need to choose the renderer on a per-cell basis, override prepareRenderer(), as shown here.
import java.awt.EventQueue;
import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableModel;
/** #see https://stackoverflow.com/a/14672312/230513 */
public class Test {
private static final Icon YES = UIManager.getIcon("InternalFrame.maximizeIcon");
private static final Icon NO = UIManager.getIcon("InternalFrame.closeIcon");
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DefaultTableModel model = new DefaultTableModel(
new Object[]{"Name", "Icon"}, 0) {
#Override
public Class<?> getColumnClass(int col) {
if (col == 1) {
return Icon.class;
} else {
return super.getColumnClass(col);
}
}
};
model.addRow(new Object[]{"One", YES});
model.addRow(new Object[]{"Two", NO});
final JTable table = new JTable(model);
table.setRowHeight(YES.getIconHeight() +2);
f.add(table);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test().display();
}
});
}
}
To take advantage of the default renderers you can override the getCellRenderer(...) method of JTable to return the appropriate renderer. Something like:
public TableCellRenderer getCellRenderer(int row, int column)
{
int modelColumn = convertColumnIndexToModel(column);
if (modelColumn == ???)
{
Class rowClass = getModel().getValueAt(row, modelColumn).getClass();
return getDefaultRenderer( rowClass );
}
else
return super.getCellRenderer(row, column);
}
Even I read and test answers by #kleopatra
How do I correctly use customer renderers to paint specific cells in a JTable?
particular one table header color java swing
about super.getTableCellRendererComponent(...) must be last code line before returns, I'm not able to write correct Renderer by those suggestion, for me works only this way
JLabel is added for Borders, HorizontalAlignment and Foreground, especially Background caused me a few non_senses by using Component instead of JLabel, (not important here somehow)
from SSCCE
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
public class SelectedTableHeader {
private JFrame frame = new JFrame("Table Demo");
private JTableHeader header;
private Object selectedColumn = null;
private String[] columnNames = {"String", "Integer", "Float", "Double", "Locale & Double", "Boolean"};
private Object[][] data = {
{"aaa", new Integer(12), new Float(12.15), new Double(100.05), new Double(12.05), true},
{"bbb", new Integer(5), new Float(7.154), new Double(6.1555), new Double(417.55), false},
{"CCC", new Integer(92), new Float(0.1135), new Double(3.1455), new Double(11.05), true},
{"ddd", new Integer(12), new Float(31.15), new Double(10.05), new Double(23.05), true},
{"eee", new Integer(5), new Float(5.154), new Double(16.1555), new Double(17.55), false},
{"fff", new Integer(92), new Float(4.1135), new Double(31.1455), new Double(3.05), true}};
private TableModel model = new DefaultTableModel(data, columnNames) {
private static final long serialVersionUID = 1L;
#Override
public Class<?> getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
};
private JTable table = new JTable(model);
public SelectedTableHeader() {
header = table.getTableHeader();
header.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
JTableHeader h = (JTableHeader) e.getSource();
int i = h.columnAtPoint(e.getPoint());
Object o = h.getColumnModel().getColumn(i).getHeaderValue();
if (i < 0) {
selectedColumn = null;
return;
}
selectedColumn = o;
h.requestFocusInWindow();
}
});
final TableCellRenderer hr = table.getTableHeader().getDefaultRenderer();
header.setDefaultRenderer(new TableCellRenderer() {
private JLabel lbl;
#Override
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (selectedColumn == value) {
lbl = (JLabel) hr.getTableCellRendererComponent(table, value, true, true, row, column);
lbl.setBorder(BorderFactory.createCompoundBorder(lbl.getBorder(), BorderFactory.createLineBorder(Color.red, 1)));
lbl.setHorizontalAlignment(SwingConstants.LEFT);
} else {
lbl = (JLabel) hr.getTableCellRendererComponent(table, value, false, false, row, column);
lbl.setBorder(BorderFactory.createCompoundBorder(lbl.getBorder(), BorderFactory.createEmptyBorder(0, 5, 0, 0)));
lbl.setHorizontalAlignment(SwingConstants.CENTER);
}
if (column == 0) {
lbl.setForeground(Color.red);
} else {
lbl.setForeground(header.getForeground());
}
/*return (value == selectedColumn) ? hr.getTableCellRendererComponent(
table, value, true, true, row, column) : hr.getTableCellRendererComponent(
table, value, false, false, row, column);*/
return lbl;
}
});
table.setRowHeight(20);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scroll = new JScrollPane(table);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scroll);
frame.pack();
frame.setLocation(150, 150);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
SelectedTableHeader selectedTableHeader = new SelectedTableHeader();
}
});
}
}
In my experience, it's better to get the DefaultTableCellHeaderRenderer when you overwrite any JTable Renderer. So, instead of messing with the JLabel from the Renderer directly, you grab the Renderer with super(). So, your code should look like this:
header.setDefaultRenderer(new DefaultTableCellHeaderRenderer() {
#Override
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
DefaultTableCellHeaderRenderer rendererComponent = (DefaultTableCellHeaderRenderer)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (selectedColumn == value) {
rendererComponent.setBorder(BorderFactory.createCompoundBorder(rendererComponent.getBorder(), BorderFactory.createLineBorder(Color.red, 1)));
rendererComponent.setHorizontalAlignment(SwingConstants.LEFT);
} else {
rendererComponent.setBorder(BorderFactory.createCompoundBorder(rendererComponent.getBorder(), BorderFactory.createEmptyBorder(0, 5, 0, 0)));
rendererComponent.setHorizontalAlignment(SwingConstants.CENTER);
}
if (column == 0) {
rendererComponent.setForeground(Color.red);
} else {
rendererComponent.setForeground(header.getForeground());
}
return rendererComponent;
}
});
To try and answer your questions directly:
Question 1:
Q: How do I correctly use customer renderers to paint specific cells in a JTable?
A: Your current code is setting a Renderer on the JTableHeader. To add a Renderer on your table cells would be similar code to what's above, only you'd set it through the Column model:
table.getColumnModel().getColumn(0).setCellRenderer(new DefaultTableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
DefaultTableCellRenderer renderer = (DefaultTableCellRenderer)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
// Set your code to render your component.
return renderer;
}
});
Note about this: JTables are column-based, which means that all the data in a certain column must be the same type (your SSCCE follows this convention). My favorite thing to do is to provide a custom Renderer for each type. For example, whenever I have a Date column, I use this renderer:
import java.awt.Component;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import org.joda.time.LocalDate;
/**
*
* #author Ryan
*/
public class DateCellRenderer extends DefaultTableCellRenderer {
String pattern;
public DateCellRenderer(String pattern){
this.pattern = pattern;
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
DefaultTableCellRenderer renderer = (DefaultTableCellRenderer)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (value != null && value instanceof LocalDate) {
renderer.setText(((LocalDate)value).toString(pattern));
} else
throw new IllegalArgumentException("Only supported Object type is LocalDate.");
return renderer;
}
}
And I call this code with something similar:
table.getColumn("Date Entered").setCellRenderer(new DateCellRenderer("MMM dd, yyyy"));
Question 2:
Q: particular one table header color java swing
A: Umm.. Your SSCCE seems to have it figured out.
Question 3:
Q: about super.getTableCellRendererComponent(...) must be last code line before returns, I'm not able to write correct Renderer by those suggestion, for me works only this way
A: I'm not sure what you mean "must be last code line before returns." That is not the case, proven by the code snip I gave above
Question 4:
Q: JLabel is added for Borders, HorizontalAlignment and Foreground, especially Background caused me a few non_senses by using Component instead of JLabel, (not important here somehow)
A: Ok... the DefaultTableCellHeaderRenderer is sufficient for all of those, borders, alignment, foreground and background.
I had this happen to me in the past and I was convinced it had to do with the Cell Renderer, but the ArraysXxxException kind of Exceptions hunted me because I had forgotten to unselect and stop editing the cell before adding/removing rows. You should try clearSelection() and table.getCellEditor().stopCellEditing(); on your JTable before remove/add and see if that solves your problem.
First, of course, make sure it is editing:
if (table.isEditing()) {
table.getCellEditor().stopCellEditing();
}