How to format contents of a JTable - java

I am using a JTable to display numerical data and strings. The numerical data default formats to the right hand side of the JTable, and the strings format to the left. I want both to be formatted into the center of the cell. I am using Nedbeans to develop the GUI but it does not seem to help with this issue.
My attempt was to create a cell renderer class that overrides the JTable default cell renderer, but I
don't know the line of code to actually change the formatting in the new cell renderer.
Any help would be appreciated.

Your thinking is correct. Within the custom TableCellRenderer, you can actually check which column/row/cell is rendered and subsequently assign a column/row/cell specific formatting.
public static class CustomTableCellRenderer extends DefaultTableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
DefaultTableCellRenderer c = (DefaultTableCellRenderer) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
// center everything in the first column
if (column == 0) {
c.setHorizontalAlignment(JLabel.CENTER);
}
// the background and border of the first cell should be gray
if (column == 0 && row == 0) {
c.setBackground(Color.GRAY);
c.setBorder(BorderFactory.createMatteBorder(0, 5, 0, 5, Color.GRAY));
}
return c;
}
}
Please note that the DefaultTableCellRenderer is called for each individual cell.
All available formatting functions are well described in the respective documentation:
https://docs.oracle.com/javase/10/docs/api/javax/swing/table/DefaultTableCellRenderer.html

Related

My columns in the JTable don't get all a background color

My columns in my table don't all get a background color. If I use a checkbox in my table, it does not get a background color.
I used this code to set the background:
participantsTable.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 ? new Color(230, 230, 230): Color.WHITE);
return this;
}
});
I've tried searching the internet for a solution, but to no avail. I'm not so familiar with the JTabel that I could come up with the error myself.
Here is what shouldn't happen:
So it shouldn't look like that, but the background of the checkbox should be the same as the column to the left of it.
What am I doing wrong and how can I fix this problem?
the background of the checkbox should be the same as the column to the left of it.
Different data types use different renderers.
In your case you would also need to customize the renderer for the Boolean.class.
Or alternatively you can override the prepareRenderer(...) method of the JTable.
A basic example would be:
JTable table = new JTable( model )
{
public Component prepareRenderer(TableCellRenderer renderer, int row, int column)
{
Component c = super.prepareRenderer(renderer, row, column);
// Alternate row color
if (!isRowSelected(row))
c.setBackground(row % 2 == 0 ? getBackground() : Color.LIGHT_GRAY);
return c;
}
};
This method is invoked after the renderer for the cell has been determined so it will work for all columns of the table.
Check out Table Row Rendering for more information and examples of custom rendering using this approach.

DefaultCellRenderer() stops working when column width = 0

So, the thing is that I have a JTable which turns rows orange when the data on one of the columns is 'true' (using a class which extends DefaultCellRenderer), problem is I don't want to show that column, so I've tried removing it or setting its width to 0, but when I do that, it no longer highlights the row in orange. Is there a way to do this or does it always have to be shown info?
Thanks.
I've tried removing it or setting its width to 0, but when I do that, it no longer highlights the row in orange
I guess because the width is 0, there is nothing to render so the renderer is never invoked.
In any case, don't use a cell width of 0. As you tab through the table that column will still get focus, but the user won't know it has focus which will confuse the user.
Instead if you want to hide a column then remove the TableColumn from the TableColumnModel. You get the TableColumnModel from the JTable by using the getColumnModel() method. Removing the column from the model just prevents the column from being displayed but the data is still contained in the TableModel.
I have a JTable which turns rows orange when the data on one of the columns is 'true'
You can override the prepareRenderer(...) method of the JTable to do this easily. This will work even you have columns with different types of data so there is no need to create multiple renderers.
The basic logic is:
JTable table = new JTable(...)
{
public Component prepareRenderer(
TableCellRenderer renderer, int row, int column)
{
Component c = super.prepareRenderer(renderer, row, column);
if (!isRowSelected(row))
{
c.setBackground(getBackground());
int modelRow = convertRowIndexToModel(row);
boolean highlight = (Boolean)getModel().getValueAt(modelRow, ???);
if (highlight) c.setBackground(Color.ORANGE);
}
return c;
}
};
Check out Table Row Rendering for more information and a working example. The example on the "Data" tab does what you want.
Can you try this. I assume that you are familiar with table cell renderer. you can override the getTableCellRendererComponent method and change the color like below:
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
// Get default renderer from the table
TableCellRenderer renderer = table.getDefaultRenderer(table.getColumnClass(column));
Component comp = renderer.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, column);
if (value.equals("true") && row == 1 && col== 1){
comp.setBackground("YOUR COLOR");
}
}

How to add image and text in same JTable cell? [duplicate]

I know how to put a String into a JTable cell, and I know how to put an image into a JTable cell. But is it possible to put an image and a String into the SAME JTable cell?
The reason for this is that I have a 'status' column in my JTable, which at the moment contains either a green, amber or red image. And in order to fulfill the design requirement, I need to add some explanatory text alongside each image (so the text next to the green image would be "Online", the text next to the amber image would be "Unknown" and the text next to the red image would be "Offline"). I need to do this in a single column (or what looks/behaves like a single column) rather than two columns.
I have researched this, but found no info at all.
Yes.
You need to use a custom cell renderer. Check out How to use Tables for more details.
You actually have two choices, you could simply set the icon and the text of the cell or you could use the renderers tooltip text instead...
public class IconTextCellRemderer extend DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
setText(...);
setIcon(...);
setToolTipText(...);
return this;
}
}
Of course you need to apply the renderer to the column...
TableColumnModel tcm = table.getColumnModel();
tcm.getColumn(x).setCellRenderer(new IconTextCellRemderer());

Both row and column selection on JTable

When I click on a JTable cell I'd like to select its whole row and its whole column.
I tried to setRowSelectionAllowed(true) and setColumnSelectionAllowed(true) and then specified a selectionInterval but it select only the single cell!
How can I do that?
As #camickr has pointed out, you might need to use table rendering to do this. This might not be the best answer but this is what I can come up with:
table.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);
if (column == table.getSelectedColumn()) {
c.setBackground(new Color (57, 105, 138));
c.setForeground(Color.white);
} else if (row == table.getSelectedRow()) {
c.setBackground(new Color (57, 105, 138));
c.setForeground(Color.white);
} else {
if (row % 2 == 0) {
c.setBackground(Color.white);
c.setForeground(Color.black);
} else {
c.setBackground(new Color(242, 242, 242));
c.setForeground(Color.black);
}
}
return c;
}
});
The new Color(57, 105, 138) is my default JTable selected color (I don't know if it's different with different jdk versions). The colors in the else statement are my default JTable not selected colors. Also, add repaint() method in your listener. Hope this helps :)
You might be able to provide your own custom highlighting of the cells.
Check out Table Row Rendering for an example of how this is done at the row level.
You could see if this approach will also work at the column level. The major concern is that as column selection changes, the entire previous column will also need to be repainted. Not sure how a JTable currently handles this.

Separator between header and data in a JTable

I would like to build a simple JTable which has no gridlines apart from a single horizontal separator between the table header and table data. The separator should span the entire width of the table exactly like a JSeparator. I have managed to achieve the desired appearance using JLabels and a JSeparator placed within a GridBagLayout, however the result is somewhat unwieldy and I can't help but feel that more concise solutions exist (perhaps using a MatteBorder?). Any help would be much appreciated!
EDIT: The solution can be achieved using the single line of code:
table.getTableHeader().setBorder(new MatteBorder(0,0,1,0, Color.BLACK));
You probably did something similar:
Create a TableCellRenderer.
TableCellRenderer renderer = new DefaultTableCellRenderer() {
final JLabel headerLabel = new JLabel();
{
//setBorder(BorderFactory.createEmptyBorder());
headerLabel.setBorder(BorderFactory.createMatteBorder(0, 0, 3, 0, Color.RED));
headerLabel.setOpaque(true);
headerLabel.setBackground(Color.WHITE);
}
#Override
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
if (row == -1) {
label.setText(value.toString());
return headerLabel;
}
return super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
row, column);
}
};
Use it for the table header (row == -1). One could also used it for the cells.
for (int i = 0; i < model.getColumnCount(); ++i) {
table.getTableHeader().getColumnModel().getColumn(i).setHeaderRenderer(renderer);
}
Either use
table.showHorizontalLines(false);
table.showVerticalLines(false);
or
table.setGridColor(Color.WHITE);
I you use only a cell renderer for the header, the following might suffice:
DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
renderer.setBorder(BorderFactory.createMatteBorder(0, 0, 3, 0, Color.RED));
renderer.setOpaque(true);
renderer.setBackground(Color.WHITE);

Categories