I have a JTable looking like this:
Is it possible to add a margin for the column text?
I have tried to add a TableCellRenderer and add an EmptyBorder. Problem: the background color gets white like this:
Any idea how to add margin and keep the default background color?
public class JTableColumnMargin extends JFrame {
public JTableColumnMargin() {
Object rowData[][] = { { "Row1-Column1", "Row1-Column2", "Row1-Column3" }, { "Row2-Column1", "Row2-Column2", "Row2-Column3" } };
Object columnNames[] = { "Column One", "Column Two", "Column Three" };
JTable table = new JTable(rowData, columnNames);
for (int i = 0; i < table.getColumnCount(); i++) {
table.getTableHeader().getColumnModel().getColumn(i).setHeaderRenderer(new HeaderRenderer(table));
}
JScrollPane scrollPane = new JScrollPane(table);
this.add(scrollPane, BorderLayout.CENTER);
this.setSize(500, 150);
this.setVisible(true);
}
private static class HeaderRenderer implements TableCellRenderer {
private DefaultTableCellRenderer renderer;
private HeaderRenderer(JTable table) {
renderer = (DefaultTableCellRenderer) table.getTableHeader().getDefaultRenderer();
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
Component c = renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
JLabel label = (JLabel) c;
label.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));
return label;
}
}
public static void main(String[] args) {
new JTableColumnMargin();
}
}
Delegating to the original renderer basically is the right direction to go, just slightly differently:
use a compoundBorder of the original and the emptyBorder
nudge the original renderer to re-set the border to its original by making the padded border a UIResource
Something like:
#Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
JComponent comp = (JComponent) originalRenderer.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, column);
Border originalBorder = comp.getBorder();
comp.setBorder(new CompoundBorderUIResource(originalBorder,
BorderFactory.createEmptyBorder(0, 20, 0, 0)));
return comp;
}
It's brittle, though, as LAFs might ignore your setting: the trick works fine for WinLAF, but not at all for Nimbus - so don't know the outcome on Mac.
Try to use next header Renderer:
private static class HeaderRenderer extends JLabel implements TableCellRenderer {
private HeaderRenderer() {
setBorder(BorderFactory.createCompoundBorder(UIManager.getBorder("TableHeader.cellBorder"),BorderFactory.createEmptyBorder(0, 10, 0, 10)));
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
setText(value.toString());
return this;
}
}
Related
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;
}
}
I want to change the color of JTable row after clicking a button. I found many examples that show how to initiate a table with different colors of rows, and also how to change the color on selecting a row. However, I wonder what is the right way to change the color on clicking a JButton.
TableCellRenderer colorRenderer = new ColorRenderer();
table.setDefaultRenderer(String.class, colorRenderer);
private class ColorRenderer extends DefaultTableCellRenderer {
private static final long serialVersionUID = 1L;
#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 (hasFocus) {
setBackground(Color.cyan);
} else if (isSelected) {
setBackground(table.getSelectionBackground());
} else {
setBackground(table.getBackground());
}
return this;
}
}
Considering that you are loading data in JTable as :
public void fillTable(){
List<String> columns = new ArrayList<String>();
List<String[]> values = new ArrayList<String[]>();
columns.add("col1");
columns.add("col2");
columns.add("col3");
for (int i = 0; i < 100; i++) {
values.add(new String[] {"val"+i+" col1","val"+i+" col2","val"+i+" col3"});
}
TableModel tableModel = new DefaultTableModel(values.toArray(new Object[][] {}), columns.toArray());
tableName.setModel(tableModel);
}
Then, you can use like this class to set a rendered to JTable :
public class EvenOddRenderer implements TableCellRenderer {
public static final DefaultTableCellRenderer DEFAULT_RENDERER = new DefaultTableCellRenderer();
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
DEFAULT_RENDERER.setHorizontalAlignment(JLabel.CENTER);
Component renderer = DEFAULT_RENDERER.getTableCellRendererComponent(
table, value, isSelected, hasFocus, row, column);
((JLabel) renderer).setOpaque(true);
Color foreground, background;
Color alternate = new Color(0xC0, 0xC0, 0xF0);
Color lightBlue = new Color(204, 204, 255);
if (isSelected) {
foreground = Color.black;
background = Color.gray;
} else {
if (row % 2 == 0) {
foreground = Color.black;
background = Color.white;
} else {
foreground = Color.black;
background = lightBlue;
}
}
renderer.setForeground(foreground);
renderer.setBackground(background);
return renderer;
}
}
Like this :
TableCellRenderer renderer = new EvenOddRenderer();
tableName.setDefaultRenderer(Object.class, renderer);
tableName.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
Then you can use setRowSelectionInterval() method to select any row :
private void btn(java.awt.event.ActionEvent evt) {
int index = 0;
tableName.setRowSelectionInterval(index, index);
}
Here you are selecting the first row in JTable
In this example, you are choosing Color.gray as JTable selection color
You can change it for sure
Check out Table Row Rendering.
This approach will also work for tables that contain different data types in each column so you don't have to create custom renderers for every type of data.
So I have the following class which defines basic parameters of an error
public class Error {
public String desc;
public int rowNumber;
public int colNumber;
public int fixNumber;
public Error(String desc,int row, int col, int fix){
this.desc = desc;
rowNumber = row++;
colNumber = col++;
fixNumber = fix;
}
...
My gui Class
public class Gui extends JFrame {
AbstractTableModel model;
JTable table;
public void start(AbstractTableModel model) {
this.model = model;
table=new JTable(model){
#Override
public boolean isCellEditable(int arg0, int arg1) {
return false;
}
};
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
TableColumn column = null;
for (int i = 0; i < model.getColumnCount(); i++) {
column = table.getColumnModel().getColumn(i);
column.setPreferredWidth(120);
column.setMaxWidth(300);
column.setMinWidth(50);
column.setCellRenderer(new customCellRender());
}
JScrollPane pane = new JScrollPane(table);
pane.setPreferredSize(new Dimension(900,900));
add(pane);
setLayout(new FlowLayout());
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
setVisible(true);
}
I have attempted to make a cellRenderer but at the moment it does not have the intended effect. Because it colors all the cells.
#SuppressWarnings("serial")
public class customCellRender extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column){
Component c = null;
c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
c.setBackground(new java.awt.Color(255, 72, 72));
return c;
}
I then have a List which stores instances of the error class.What I cant figure out is how to ONLY change the color of the cells in my table based on the Error(rowNumber,colNumber). Considering that the errors are in a list structure, so I would have to iterate over and somehow pass each error column and row to the renderer. Is that possible ?
Your code colors all the cells because the component is reused, not recreated every time. Just add a
if (error) {
c.setBackground(errorBackground);
} else {
c.setBackground(table.getBackground);
}
A couple of points to make:
Don't create a new Color every time. It's expensive and you're using the same one anyway.
Use a Set for your errors to make contains quick, otherwise your rendering may become very slow with a large number of those.
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.