Let's say I have the following JTable, which is displayed as soon as a button is pressed:
| Name
------+------------
True | Hello World
False | Foo Bar
True | Foo
False | Bar
I want to render the cells that were initially true to a JCheckBox, and all cells that were initially false to not display anything (no JCheckBox). The user could check or un-check the JCheckBoxes in the cells that were initially true, which would do something to a chart I created.
Right now, my cell renderer displays JCheckBoxes in all cells, including those that were initially false (it displays those JCheckBoxes without check marks), but I want to not display anything in the latter. Here is my code:
protected class CheckBoxCellRenderer extends JCheckBox implements TableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (!(Boolean) tableModel.getValueAt(row, 0)) {
NoCheckBoxCellRenderer renderer = new NoCheckBoxCellRenderer();
return renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
}
this.setSelected((Boolean) tableModel.getValueAt(row, 0));
return this;
}
}
protected class NoCheckBoxCellRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
this.setVisible(false);
return this;
}
}
In the if statement, I tried using this.setVisible(false) before using NoCheckBoxCellRenderer, but it wasn't working. I'm thinking about using multiple cell renderers to accomplish this task. Would it be possible to do so? Any advice would be greatly appreciated!
Store Boolean.TRUE for the true values. Then store an empty String for the false values. You will then need to:
a) override the getCellRenderer(...) method to return the appropriate renderer for the data found in the cell.
b) make the cells containing the empty string non-editable:
JTable table = new JTable(data, columnNames)
{
public TableCellRenderer getCellRenderer(int row, int column)
{
if (column == 0)
{
Class cellClass = getValueAt(row, column).getClass();
return getDefaultRenderer( cellClass );
}
return super.getCellRenderer(row, column);
}
public boolean isCellEditable(int row, int column)
{
Class cellClass = getValueAt(row, column).getClass();
if (column == 0 && cellClass instanceof Boolean)
{
return true;
}
else
{
return false;
}
return super.isCellEditable(row, column);
}
};
Using this approach there is no need for custom renderers or editors.
Have getTableCellRendererComponent return a blank JLabel if the initial value was false.
Related
I have a JTable on a Netbeans 8.2 project which shows the data of a list a class (let's call it Client) and a checkbox on the first column of each line. I've setup this way changing the data type of the column in the object's properties menu. How can I not show this checkbox in case that a client's attribute is false?
I assume the first column is not editable. If you want to hide the JCheckBox when cell value is false, you can use a customer cell renderer:
private class MyCellRenderer extends DefaultTableCellRenderer
{
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col)
{
Component c;
if (((Boolean)value).equals(true))
{
// Use the default renderer for Boolean which is JCheckBox based
c = myTable.getDefaultRenderer(table.getColumnClass(col)).getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
} else
{
// Use the standard default renderer which is a JLabel
c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
if (c instanceof JLabel)
{
((JLabel) c).setText(null);
}
}
return c;
}
}
And apply it on the first boolean column:
myTable.getColumnModel().getColumn(0).setCellRenderer(new MyCellRenderer());
I am new to programming and need help with rendering cells in a JTable.
I have implemented a custom cell renderer but don't know how to get custom components. getTableCellRendererComponent only accepts int,bool, table and Object.
Here is my code which works great with any of those data types.
But what i need to do is render the cells based on a LocalTime value and a String value. What am I missing?
public class MyTableCellRenderer extends DefaultTableCellRenderer {
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);
//Here is what I want to accomplish with LocalTime values or String values
if (SomeLocalTime > SomeOtherLocalTime)){
c.setForeground(Color.red);
} else {
c.setForeground(table.getForeground());
}
return c;
}
}
Please help
I got it working but now I cant render 2 different columns with different criteria. It's only returning the value from the second if where column ==3.
Do I need to have 2 TableCellRenderers for one table? Is that even possible and if so, how?
Here is my updated code:
public class MyTableCellRenderer extends DefaultTableCellRenderer {
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 (value instanceof Time && column == 2) {
if (((Time) value).toLocalTime().isAfter(gracePeriodStartTime)) {
c.setForeground(Color.red);
}
} else {
c.setForeground(table.getForeground());
}
if (value instanceof Time && column == 3) {
if (((Time) value).toLocalTime().isBefore(gracePeriodEndTime)) {
c.setForeground(Color.red);
}
} else {
c.setForeground(table.getForeground());
}
return c;
}
}
Your if condition is wrong:
if (SomeLocalTime.isAfter(SomeOtherLocalTime)) {
c.setForeground(Color.RED);
} else {
c.setForeground(table.getForeground());
}
This should get you further along. Leave a comment if you need more help.
I have a JTable, that I want I want to be able to change the color of a single cell that is clicked on.
Here is a simplified version of my code:
public class TableFrame extends JFrame {
public TableFrame() {
JTable table = new JTable(8, 8);
table.setGridColor(Color.BLACK);
table.setDefaultRenderer(CustomCellRenderer.class, new CustomCellRenderer());
getContentPane().add(table);
}
public class CustomCellRenderer extends DefaultTableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JLabel l = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (hasFocus) {
l.setBackground(Color.red);
l.setText("Hello");
}
return l;
}
}
}
When I click a certain cell, I expect it to change color to red and add "Hello" to it. It changes the text, but for some weird reason, it changes the color of all the cells after it? And when I click an uncolored cell, it does the same, but not always in an organised way if that makes sense? Like, it won't color all the cells after it, but maybe some that are just above and leave others blank..
It's really weird and makes no sense whatsoever. What is happening??
Having dug around the DefaultTableCellRenderer class a bit, when you call setBackground on the JLabel component, which is backing the DefaultTableCellRenderer, it is storing the value you use...
public void setBackground(Color c) {
super.setBackground(c);
unselectedBackground = c;
}
When the cell is painted again, it's this value (unselectedBackground) which is been used to repaint the cell in "default" mode...
if (isSelected) {
//...
} else {
Color background = unselectedBackground != null
? unselectedBackground
: table.getBackground();
if (background == null || background instanceof javax.swing.plaf.UIResource) {
Color alternateColor = DefaultLookup.getColor(this, ui, "Table.alternateRowColor");
if (alternateColor != null && row % 2 != 0) {
background = alternateColor;
}
}
super.setForeground(unselectedForeground != null
? unselectedForeground
: table.getForeground());
super.setBackground(background);
}
This means, the moment you use setBackground and pass it Color.RED, the DefaultTableCellRenderer assumes that this becomes the default color for ALL unselected cells.
The only choice you have is to reset the background color manually, for example...
public class CustomCellRenderer extends DefaultTableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JLabel l = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (hasFocus) {
l.setBackground(Color.red);
l.setText("Hello");
} else if (!isSelected) {
l.setBackground(table.getBackground());
}
return l;
}
}
Also, you should really be using something more like...
table.setDefaultRenderer(Object.class, new CustomCellRenderer());
to register the cell renderer, as it's the Class type returned by TableModel#getColumnClass which determines which cell renderer is used ;)
Since the OP only wants help with the rendered and not with the data... here goes (assuming there is a function called hasBeenClicked(row,column) method available to determine whether the cell has been visited yet.
public class CustomCellRenderer extends DefaultTableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JLabel l = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (hasBeenClicked(row,column)) {
l.setBackground(Color.red);
l.setText("Hello");
} else {
// reset the label to white background
l.setBackground(Color.white);
l.setText("Hello");
}
return l;
}
}
}
Also note that the registration of the renderer should be
table.setDefaultRenderer(Object.class, new CustomCellRenderer());
Since we want all columns to have this renderer (renderers are registered against the class of the column in the model).
I tested with the below as the hasBeenClicked method.
public boolean hasBeenClicked(int row, int column){
return (row%2==0 && column%2==0);
}
Just implement your own tracking of whether a cell has been clicked or not and you should be good to go. Remember that you should not use the renderer to track the clicks, use some kind of listener instead.
I have 3 columns in JTable. One column is editable. Other columns are non-editable. Editable column should be displayed green color and non-editable column should be in red color. I have tried with DefaultRenderer class but its not working. Please if anyone know this, help me.
Well there are few ways to do this. Following 1 will render the column 1 as grey.
JTable table = new JTable() {
public Component prepareRenderer(TableCellRenderer renderer,
int rowIndex, int vColIndex) {
Component c = super.prepareRenderer(renderer, rowIndex, vColIndex);
if (vColIndex == 0) {//if first column
c.setBackground(Color.red);
} else {
c.setBackground(Color.green);
}
return c;
}
};
Or you can have class override DefaultTableCellRenderer like following 2
public class CustomTableCellRenderer extends DefaultTableCellRenderer
{
public Component getTableCellRendererComponent (JTable table, Object obj,
boolean isSelected, boolean hasFocus, int row, int column){
Component cell = super.getTableCellRendererComponent(table, obj,
isSelected, hasFocus, row, column);
if (column == 0){
cell.setBackground(Color.red);
}
else{
cell.setBackground(Color.green);
}
return cell;
}
}
I have a table with a custom table model which has two columns. Column 0 is an ImageIcon class, and Column 1 is a String class.
public Class<?> getColumnClass(int col) {
if (col == 0) {
return ImageIcon.class;
} else {
return String.class;
}
}
When I define a new TableCellRenderer class to be added to the columns so I can style the cells, it overwrites the ImageIcon class and sets it to a String.
public class CustomTableCellRenderer extends DefaultTableCellRenderer
{
public Component getTableCellRendererComponent (JTable table, Object obj, boolean isSelected, boolean hasFocus, int row, int
column)
{
Component cell = super.getTableCellRendererComponent(table,
obj, isSelected, hasFocus, row, column);
if(isSelected)
cell.setBackground(Color.BLUE);
return cell;
}
}
Any ideas on how to fix this?
My mistake, it is sort of hidden:
When I define a new TableCellRenderer class to be added to the columns so I can style the cells, it overwrites the ImageIcon class and sets it to a String.
So the problem is that, when I define this TableCellRenderer class to style my table, the ImageIcon columns in my table turn to Strings like "File:..." instead of the actual icon.
There is no need to create a custom renderer. JTable allready supports a default renderer for columns containing an Icon. All you need to do is override the getColumnClass() method, which you appear to be doing.
Another possible solution is to just set the icon yourself. I'm not sure if this is the best solution, but it works:
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
Component cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row,
column);
((JLabel)cell).setIcon((Icon)value);
((JLabel)cell).setText("");
((JLabel)cell).setHorizontalAlignment(JLabel.CENTER);
if (isSelected) {
cell.setBackground(Color.blue);
} else {
cell.setBackground(null);
}
return cell;
}