Both row and column selection on JTable - java

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.

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.

How to format contents of a JTable

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

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

Java- Coloring matching cells in two different JTables

I am writing a utility that will compare metadata fields from a SQL database. I am able to get all of the data into a JTable. I am trying to now color each particular cell depending on if they match the cell of another JTable. From my understanding I need to write a CellRenderer (Change the color of specific rows in my JTable). I had thought doing something like the below to compare the two values would be the best solution
for(int i=0;i<col2;i++){
for(int j=0;j<row2;j++){
if(table1.getValueAt(i,j).equals(table2.getValueAt(i,j))){
table1.setSelectionBackground(Color.GREEN);
table2.setSelectionBackground(Color.GREEN);
}else if(!(table1.getValueAt(i, j).equals(table2.getValueAt(i, j)))){
table1.setSelectionBackground(Color.RED);
table2.setSelectionBackground(Color.RED);
}
}
}
I know the that the setSelectionBackground is not the method I want to call. I'm confused on how to write the CellRenderer listed in the above post to change the background color of a cell in depending if the contents match each other. Is writing the custom CellRenderer the only option?
EDIT 1:
As of right now, it appears to be taking in the correct color for background but it is coloring the entire table rather than a specific cell. Below is my CellRenderer and one of the for loops for how I think I should be calling the setBackground method
private class CellRenderer extends DefaultTableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value,boolean isSelected,boolean hasFocus,int row, int col){
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
this.setOpaque(true);
this.setBackground(table.getBackground());
return this;
}
int col1 = table1.getColumnCount()-1;
int row1 = table1.getRowCount()-1;
int col2 = table2.getColumnCount()-1;
int row2 = table2.getRowCount()-1;
table1.setDefaultRenderer(Object.class, new CellRenderer());
table2.setDefaultRenderer(Object.class, new CellRenderer());
if(row1>row2){
if(col1>col2){
for(int i=0;i<row2;i++){
for(int j=0;j<col2;j++){
if(table1.getValueAt(i,j).equals(table2.getValueAt(i,j))){
color = Color.GREEN;
System.out.println(color);
table1.setBackground(color);
table2.setBackground(color);
}else if(!(table1.getValueAt(i, j).equals(table2.getValueAt(i, j)))){
color = Color.RED;
System.out.println(color);
table1.setBackground(color);
table2.setBackground(color);
}
}
}

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