Class specific renderer component not called - java

I've a JTable set to display String and Boolean values in the same column. I've the following piece of code to setup renderers for both the object types.
table.setDefaultRenderer(Boolean.class, new BooleanHandler());
table.setDefaultRenderer(String.class, new StringHandler());
table.setDefaultRenderer(
Object.class,
new DefaultTableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
System.out.println("Inside overridden function");
return super.getTableCellRendererComponent(table, value, isSelected, hasFocus,row, column);
}
}
);
The issue I face is that, the renderer for Object gets called always instead of Boolean or String. I tried removing the renderer for Object, still no luck.

I've a JTable set to display String and Boolean values in the same column
Then you can't just use the normal rendering logic.
Normally the renderer is choosen based on the value returned by the getColumnClass(...) method. However, this is column based, not cell based so you won't know which renderer to return.
Instead you need to override the getCellRenderer(...) and getCellEditor(...) methods to return the renderer/editor based on the data in the cell.
An example of this approach is given below:
import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class TablePropertyEditor extends JFrame
{
public TablePropertyEditor()
{
String[] columnNames = {"Type", "Value"};
Object[][] data =
{
{"String", "I'm a string"},
{"Date", new Date()},
{"Integer", new Integer(123)},
{"Double", new Double(123.45)},
{"Boolean", Boolean.TRUE}
};
JTable table = new JTable(data, columnNames)
{
private Class editingClass;
public TableCellRenderer getCellRenderer(int row, int column)
{
editingClass = null;
int modelColumn = convertColumnIndexToModel(column);
if (modelColumn == 1)
{
Class rowClass = getModel().getValueAt(row, modelColumn).getClass();
return getDefaultRenderer( rowClass );
}
else
return super.getCellRenderer(row, column);
}
public TableCellEditor getCellEditor(int row, int column)
{
editingClass = null;
int modelColumn = convertColumnIndexToModel(column);
if (modelColumn == 1)
{
editingClass = getModel().getValueAt(row, modelColumn).getClass();
return getDefaultEditor( editingClass );
}
else
return super.getCellEditor(row, column);
}
// This method is also invoked by the editor when the value in the editor
// component is saved in the TableModel. The class was saved when the
// editor was invoked so the proper class can be created.
public Class getColumnClass(int column)
{
return editingClass != null ? editingClass : super.getColumnClass(column);
}
};
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane( table );
getContentPane().add( scrollPane );
}
public static void main(String[] args)
{
TablePropertyEditor frame = new TablePropertyEditor();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}
The above code just uses the default String and Boolean renderers and editors.
The other approach would be to create custom renderers and editors so that each is aware of the two possible data types and returns the appropriate renderer/editor.

Related

change color JTable cells with getTableCellRendererComponent NOTHING HAPPENDS

I am trying to change the color of some cells in my JTable. I have tried to override getTableCellRendererComponent in a simple example, and it works nice. But when I do the same in my project nothing changes...
I have my JPanel with my JTable in a Box like this:
boxTable=Box.createHorizontalBox();
box2Table.add(boxTable);
//JTable
tablaContador = new JTable(datosContador,cabeceraContador);
//MODIF COLOR
tablaContador.setDefaultRenderer(Object.class, new ColorRenderer());
Doing:
System.out.println(tablaContador.getColumnClass(3));
I can know that the first parameter of setDefaultRenderer is Object.class
I don't know if the problem is here... i have only strings in the Table, but I have tried String.class and nothing happens
Then I modify some things of JTable's Cells:
tablaContador.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
boxTable.add(tablaContador);
//Align cells
for (int i=0; i<cabeceraContador.length;i++){
tablaContador.getColumnModel().getColumn(i).setCellRenderer(alinearCeldas);
}
//Modify cells' width
tablaContador.getColumnModel().getColumn(0).setMinWidth(150);
for (int i=1; i<cabeceraContador.length;i++){
tablaContador.getColumnModel().getColumn(i).setMaxWidth(40);
}
//Scroll for the Table
scrollContador=new JScrollPane(tablaContador,JScrollPane.VERTICAL_SCROLLBAR_NEVER,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollContador.setPreferredSize(new Dimension(1000,80));
scrollContador.setMinimumSize(new Dimension(1000,80));
scrollContador.setMaximumSize(new Dimension(2000,80));
//Add scroll to the box
box2Table.add(scrollContador);
And my ColorRenderer class is:
public class ColorRenderer extends DefaultTableCellRenderer{
private Component c;
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,int row, int column) {
c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
c.setBackground(Color.BLUE);
return c;
}
}
Table result
So It does not work in my project i don't know why
any idea?
thaks!
I see:
tablaContador.setDefaultRenderer(Object.class, new ColorRenderer());
and then I see:
for (int i=0; i<cabeceraContador.length;i++)
{
tablaContador.getColumnModel().getColumn(i).setCellRenderer(alinearCeldas);
}
The assignment of the renderer to a specific column takes precedence over setting the default renderer so your color renderer is never used.
Not exactly what you are trying to do, but I would guess you need to add the color rendering logic to the alignment renderer. In other words all the rendering logic must be contained in a single renderer. You can't merge multiple renderers.
Here is a simple example of a custom renderer:
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
public class TableRenderer extends JPanel
{
public TableRenderer()
{
String[] columnNames = {"String", "Integer"};
Object[][] data =
{
{"A", new Integer(1)},
{"B", new Integer(2)},
{"C", new Integer(10)},
{"D", new Integer(4)}
};
DefaultTableModel model = new DefaultTableModel(data, columnNames);
JTable table = new JTable( model );
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane( table );
add( scrollPane );
// Override default renderer on a specific column
TableCellRenderer colorRenderer = new ColorRenderer();
table.getColumnModel().getColumn(1).setCellRenderer( colorRenderer );
}
/*
** Color the focused cell
*/
class ColorRenderer extends DefaultTableCellRenderer
{
public ColorRenderer()
{
super();
setHorizontalAlignment(JLabel.RIGHT);
}
#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 (isSelected)
setBackground( table.getSelectionBackground() );
else
{
setBackground( null );
try
{
int number = Integer.parseInt( value.toString() );
if (number > 9)
setBackground( Color.RED );
}
catch(Exception e) {}
}
return this;
}
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("Color Renderer");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TableRenderer());
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}

How to set cell background and decimal format together during cell selection

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) : "");
}
}
}

Jtable with different types of cells depending on data type

How can I implement a JTable with different types of cell editors depending on the type of input a particular row is displaying?
For example
some rows could be checkboxes (for boolean types)
some rows could be comboboxes (if I want to provide a fixed set of options to choose from)
some rows could be text fields (if I allow arbitrary data).
Currently I have implemented the AbstractTableModel, which takes a set of custom field objects from my object and adds rows to the table. I would like to further customize my table by setting specific types of cells. I can determine which cell type to use based on the type of field that row contains.
The table model is dynamically created at run-time.
some rows could be checkboxes (for boolean types)
some rows could be comboboxes (if I want to provide a fixed set of options to choose from)
some rows could be text fields (if I allow arbitrary data).
for example
import java.awt.EventQueue;
import java.util.Date;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
public class EachRowRendererEditor {
private JFrame frame = new JFrame("EachRowRendererEditor");
private String[] columnNames = {"Type", "Value"};
private Object[][] data = {
{"String", "I'm a string"},
{"Date", new Date()},
{"Integer", new Integer(123)},
{"Double", new Double(123.45)},
{"Boolean", Boolean.TRUE}};
private JScrollPane scrollPane;
private JTable table;
public EachRowRendererEditor() {
table = new JTable(data, columnNames) {
private static final long serialVersionUID = 1L;
private Class editingClass;
#Override
public TableCellRenderer getCellRenderer(int row, int column) {
editingClass = null;
int modelColumn = convertColumnIndexToModel(column);
if (modelColumn == 1) {
Class rowClass = getModel().getValueAt(row, modelColumn).getClass();
return getDefaultRenderer(rowClass);
} else {
return super.getCellRenderer(row, column);
}
}
#Override
public TableCellEditor getCellEditor(int row, int column) {
editingClass = null;
int modelColumn = convertColumnIndexToModel(column);
if (modelColumn == 1) {
editingClass = getModel().getValueAt(row, modelColumn).getClass();
return getDefaultEditor(editingClass);
} else {
return super.getCellEditor(row, column);
}
}
// This method is also invoked by the editor when the value in the editor
// component is saved in the TableModel. The class was saved when the
// editor was invoked so the proper class can be created.
#Override
public Class getColumnClass(int column) {
return editingClass != null ? editingClass : super.getColumnClass(column);
}
};
table.setPreferredScrollableViewportSize(table.getPreferredSize());
scrollPane = new JScrollPane(table);
frame.add(scrollPane);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
EachRowRendererEditor eeee = new EachRowRendererEditor();
}
});
}
}
Create a custom class implementing javax.swing.table.TableCellRenderer, which displays the values using the control you want to display with depending on the data type. Use instances of this class as cell renderer (TableColumn.setCellRenderer)

JTable cell with two data types

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);
}

How to use Renderer for TableHeader

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();
}

Categories