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);
}
Related
Main class:
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NewMDIApplication().setVisible(true);
new TestTable();
}
});
}
public JTable getMyJTable() {
return jTable2;
}
Other class:
package javaapplication9;
import java.awt.Color;
import javax.swing.table.DefaultTableModel;
public class TestTable extends NewMDIApplication {
public NewMDIApplication obj=new NewMDIApplication();
public TestTable() {
final DefaultTableModel model = (DefaultTableModel) obj.getMyJTable().getModel();
obj.getMyJTable().setModel(model);
obj.getMyJTable().setDefaultRenderer(obj.getMyJTable().getClass(), new MyCellRenderer());
}
public class MyCellRenderer extends javax.swing.table.DefaultTableCellRenderer {
public java.awt.Component getTableCellRendererComponent(javax.swing.JTable table, java.lang.Object value, boolean isSelected, boolean hasFocus, int row, int column) {
final java.awt.Component cellComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
Object val = table.getValueAt(row, 1);
String sval = val.toString();
if (sval.equalsIgnoreCase("A")) {
cellComponent.setForeground(Color.black);
cellComponent.setBackground(Color.red);
} else {
cellComponent.setBackground(Color.white);
cellComponent.setForeground(Color.black);
}
if (isSelected) {
cellComponent.setForeground(table.getSelectionForeground());
cellComponent.setBackground(table.getSelectionBackground());
}
return cellComponent;
}
}
}
This program is running.... but not showing any error. But when I edit some data of table through combo box, the color of table is not changing at runtime .
What would be a solution to this problem?
There are two aspects to JTable cells: a renderer, and an editor. The renderer is used to display the cells, the editor is used when a cell is edited. You have the renderer done, but not the editor.
Supply the JTable with an editor that colors the edited cell the same way the renderer does. E.g. by way of the JTable.setDefaultEditor(Class<?> columnClass, TableCellEditor editor) method.
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);
}
...
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 celltable with 4 column (name size addedBy modifiedBy )
all the value is filled during the run time.
The table actully show the documents.
Documents can be pdf, txt , doc so
i want to add icon before the name of the document.
and i also want one more Image column before name column
My code so far.
*
private CellTable<FDocument> getDocumentTable() {
if (documentTable == null) {
documentTable = new CellTable<FDocument>();
documentTable.setSize("600px", "300px");
documentTable.addColumn(nameColumnD, "NAME");
documentTable.addColumn(sizeColumnD, "SIZE");
documentTable.addColumn(modified_by_ColumnD, "MODIFIED BY");
documentTable.addColumn(dateColumnD, "MODIFIED ON");
}
return documentTable;
}
TextColumn<FDocument> idColumnD = new TextColumn<FDocument>() {
#Override
public String getValue(FDocumentobject) {
// TODO Auto-generated method stub
return object.getId();
}
};
TextColumn<FDocument> nameColumnD = new TextColumn<FDocument>() {
#Override
public String getValue(FDocumentobject) {
return object.getName();
}
};
TextColumn<FDocument> sizeColumnD = new TextColumn<FDocument>() {
#Override
public String getValue(FDocumentobject) {
return object.getSize();
}
};
TextColumn<FDocument> modified_by_ColumnD = new TextColumn<FDocument>() {
#Override
public String getValue(FilenetDocument object) {
return object.getModifiedBy();
}
};
TextColumn<FDocument> dateColumnD = new TextColumn<FDocument>(){
#Override
public String getValue(FDocumentobject){
return object.getModifiedOn();
}
};
private void addValuesToTable(){
List<FDocument> FDC = null;
/*
* Adding data to folder Table
*/
ArrayList<FDocument> documentsArrayList = new ArrayList<FDocument>();
Iterator<String> iteratorDocument = documents.getDocuments().getDocumentCollection().keySet().iterator();
while(iteratorDocument.hasNext()){
String key = iteratorDocument.next().toString();
FDocument value = documents.getDocuments().getDocumentCollection().get(key);
documentsArrayList.add(new FDocument(value.getName(), value.getSize(),value.getModifiedBy(), value.getModifiedOn(),value.getId()));
}
FDC = documentsArrayList;
// Create a data provider.
ListDataProvider<FDocument> dataProvider1 = new ListDataProvider<FDocument>();
// Connect the table to the data provider.
dataProvider1.addDataDisplay(documentTable);
// Add the data to the data provider, which automatically pushes it to the widget.
List<FDocument> listDocument = dataProvider1.getList();
for (FDocument fDocument: FDC) {
listDocument.add(fDocument1);
}
This the way i have made my table and the value.
Plz any one tell me the procedure
to add icon before the name of the document.
and i also want one more Image column before name column
Use DefaultTableCellRenderer to set custom renderer against the column with the desired icon. As shown below, the renderer creates a new label to mask all the cells within the selected column.
private class CellRenderer extends DefaultTableCellRenderer
{
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
JLabel label = new JLabel((String)value);
label.setOpaque(true);
Icon icon = new ImageIcon("icon.png");
label.setIcon(icon);
return label;
}
}
And then apply it to your table as shown below:
table.getColumnModel().getColumn(0).setCellRenderer(new CellRenderer());
Edited:
If you're using GWT then see here for an example code for Grid Cell format.
For creating image column, You need to define a custom renderer that sets the icon on the label
import java.awt.Component;
import javax.swing.ImageIcon;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
public class MyRenderer extends DefaultTableCellRenderer {
/*
* #see TableCellRenderer#getTableCellRendererComponent(JTable, Object, boolean, boolean, int, int)
*/
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int column) {
ImageIcon icon = new ImageIcon(getClass().getResource("images/moon.gif"));
setText((String)value);
setIcon(icon);
return this;
}
}
And then, use the renderer in a table as follows,
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
public class Sample {
public static void main(String[] args) {
JFrame f = new JFrame("Sample");
f.getContentPane().setLayout(new GridLayout(1,0,0,0));
TableModel model = new AbstractTableModel() {
public Object getValueAt(int rowIndex, int columnIndex) {
return rowIndex + "," + columnIndex;
}
public int getColumnCount() {
return 3;
}
public int getRowCount() {
return 10;
}
};
JTable table = new JTable(model);
table.getColumnModel().getColumn(1).setCellRenderer(new MyRenderer());
JScrollPane pane = new JScrollPane(table);
f.getContentPane().add(pane);
f.pack();
f.setVisible(true);
}
}
Both of these will probably need a custom TableCellRenderer...
Refer to the API docs here... http://docs.oracle.com/javase/1.4.2/docs/api/javax/swing/table/DefaultTableCellRenderer.html
You basically want to overwrite the getTableCellRendererComponent() method, and add in any additional code for rendering the image.
For example, to add an icon before the document, you would do the following...
public void MyTableCellRenderer extends DefaultTableCellRenderer {
public MyTableCellRenderer(){
super();
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column){
Component renderer = super.getTableCellRendererComponent(table,value,isSelected,hasFocus,row,column);
if (row == 0 && renderer instanceof JLabel){ // where row == 0 is the row you want to add the icon to
((JLabel)renderer).setIcon(new ImageIcon("image.png"));
}
return renderer;
}
}
You would need to set this as the TableCellRenderer for the column or table.
You would also do a similar thing for adding an image column to the table.
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();
}