Look-and-feel issue when centering JTable column header - java

I am using the following code:
public final class TableCellRendererCenter extends DefaultTableCellRenderer {
public static final TableCellRenderer INSTANCE
= new TableCellRendererCenter();
protected TableCellRendererCenter() {
// Calling super
super();
this.setHorizontalAlignment(SwingConstants.CENTER);
}
}
on a JTable column:
TableColumnModel retrMod = ChartItemsTable.getColumnModel();
TableColumn retrCol = retrMod.getColumn(2);
retrCol.setHeaderRenderer(TableCellRendererCenter.INSTANCE);
retrCol.setCellRenderer(TableCellRendererCenter.INSTANCE);
and the look-and-feel does not match other column headers anymore:
Why? How can I solve this issue?
EDIT
It seems like NetBeans is using DefaultTableCellHeaderRenderer which is coming from package sun.swing.table;
I read everywhere that I should not use sun packages. Grrrr... this does not help!
EDIT 2
The suggestion of 0verbose produces the following:
SOLUTION
Following eugener's suggestion, I updated my code as following:
public final class TableCellRendererCenter extends DefaultTableCellRenderer {
#Override
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
// returns component used for default header rendering
// makes it independent on current L&F
Component retr = table.getTableHeader().getDefaultRenderer().
getTableCellRendererComponent(
table, value, isSelected, hasFocus, row, column);
if ( JLabel.class.isAssignableFrom(retr.getClass()) ) {
JLabel jl = (JLabel) retr;
jl.setHorizontalAlignment(SwingConstants.CENTER);
}
return retr;
}
#Override
public void validate() {}
#Override
public void revalidate() {}
#Override
public void firePropertyChange(
String propertyName, boolean oldValue, boolean newValue) {}
#Override
public void firePropertyChange(
String propertyName, Object oldValue, Object newValue) {}
}
And I get this:
Look-and-feel is preserved and column header is centered !!! (Other column headers are centered too, but I can control this by making further tests on the int row, int column parameters).

The issue is that you are using different cell renderer then the one used by your LAF. IMO the only way to achieve proper LAF is to use renderer already provided by LAF itself such as:
public class TableHeaderRenderer extends JComponent implements TableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
// returns component used for default header rendering
// makes it independent on current L&F
return table.getTableHeader().getDefaultRenderer().
getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
}
// following methods are overriden for performance reasons
#Override
public void validate() {}
#Override
public void revalidate() {}
#Override
public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {}
#Override
public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {}
}
Obviously, once you have proper renderer, you can cast it to a JLabel (after checking that it is, of course) and then center your text or do something else.

maybe you can try refactor yourclass this way :
public class TableCellRendererCenter extends JLabel implements TableCellRenderer{
public TableCellRendererCenter(JTable associatedTable){
this.table = associatedTable;
JTableHeader header = this.table.getTableHeader();
this.setHorizontalAlignment(SwingConstants.CENTER);
this.setForeground(header.getForeground());
this.setBackground(header.getBackground());
this.setFont(header.getFont());
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
return this;
}}
EDIT:
I checked right now. DefaultTableCellRenderer already extends JComponent. So it's possible that only these lines are needed:
this.setForeground(header.getForeground());
this.setBackground(header.getBackground());
this.setFont(header.getFont());
(I'm not sure. I did something similar but not for column header and not extending DefaultTableCellRenderer)

Related

How can I add custom JComponent in a single JTable cell?

I want to make a JTable , where one single cell (not all rows of a column) will contain a JComponent like JdatePicker or JComboBox.
I have written this code
DefaultTableModel dm;
dm = new DefaultTableModel() {
public boolean isCellEditable(int rowIndex, int columnIndex) {
return !(columnIndex == 0); //make 0th column non-editable
}
};
Object [] columnHeaders=new Object[]{"Field", "Value"};
Object [][] data=new Object[][]{{"ID",""},{"Reg Year",""},{"Reg Date", ""}} ;
regFormTable.setModel(dm); //regFormTable is a Jtable object
I also have a class that implements TableCellrenderer:
public class datePickerCellRenderer extends JFrame implements TableCellRenderer{
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
this.add(new JDateChooser());
return this;
}
}
How can I use datePickerCellRenderer class to implement as I described. I tried a few ways. None of those worked.
[Using Netbeans GUI builder is there a way to do that?]
Plaese ask if any more code I need to add

how to use custom cell rendering in jtable for the below needs? [duplicate]

I would like to make an editable table and then check the data to make sure its valid. Im not sure how to change the color of just one cell. I would like to get a cell, for example (0,0) and color the foreground to red. I have read the other posts on SO as well as Oracle about the custom ColorRenderer, but i just don't get how i would use this.
Thanks.
Say that the cell you would like to render with a different color represents a status (I'll take Rejected and Approved as examples). I'd then implement a method in my table model called getStatus(int row) which returns the status for any given row.
Then, when that is in place, I'd go about creating a cell renderer responsible for rendering the column which the cell belongs to. The cell renderer would be something in the lines of the below code.
public class StatusColumnCellRenderer extends DefaultTableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
//Cells are by default rendered as a JLabel.
JLabel l = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
//Get the status for the current row.
CustomTableModel tableModel = (CustomTableModel) table.getModel();
if (tableModel.getStatus(row) == CustomTableModel.APPROVED) {
l.setBackground(Color.GREEN);
} else {
l.setBackground(Color.RED);
}
//Return the JLabel which renders the cell.
return l;
}
Then, when the renderer is in place, simply "apply" the renderer to the table with the following piece of code:
Table.getColumnModel().getColumn(columnIndex).setCellRenderer(new StatusColumnCellRenderer());
With regard to making a cell editable, simply implement the isCellEditable(int rowIndex, int columnIndex) method in your table model. You also need to implement the method
setValueAt(Object value, int rowIndex, int columnIndex) if you would like to keep the value which the user provides (which i assume you do!).
I would like to make an editable table and then check the data to make sure its valid.
Another approach would be to edit the data before it is saved to the table model to prevent invalid data from being entered.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.event.*;
import javax.swing.border.*;
import javax.swing.table.*;
public class TableEdit extends JFrame
{
TableEdit()
{
JTable table = new JTable(5,5);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollpane = new JScrollPane(table);
getContentPane().add(scrollpane);
// Use a custom editor
TableCellEditor fce = new FiveCharacterEditor();
table.setDefaultEditor(Object.class, fce);
}
class FiveCharacterEditor extends DefaultCellEditor
{
FiveCharacterEditor()
{
super( new JTextField() );
}
public boolean stopCellEditing()
{
try
{
String editingValue = (String)getCellEditorValue();
if(editingValue.length() != 5)
{
JTextField textField = (JTextField)getComponent();
textField.setBorder(new LineBorder(Color.red));
textField.selectAll();
textField.requestFocusInWindow();
JOptionPane.showMessageDialog(
null,
"Please enter string with 5 letters.",
"Alert!",JOptionPane.ERROR_MESSAGE);
return false;
}
}
catch(ClassCastException exception)
{
return false;
}
return super.stopCellEditing();
}
public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column)
{
Component c = super.getTableCellEditorComponent(
table, value, isSelected, row, column);
((JComponent)c).setBorder(new LineBorder(Color.black));
return c;
}
}
public static void main(String [] args)
{
JFrame frame = new TableEdit();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}
I believe the correct way to do colouring in a table is via a ColorHighlighter. The table renderers have problems to render different colours in the same column.
Here is an example of how to use highlighters. In this case it is for highlighting a cell that is not editable.
public class IsCellEditablePredicate implements HighlightPredicate {
private JXTable table;
public IsCellEditablePredicate (final JXTable table) {
this.table = table;
}
#Override
public boolean isHighlighted(Component component, ComponentAdapter componentAdapter) {
return !table.isCellEditable(componentAdapter.row,
componentAdapter.column);
}
}
and then in your code for setuping the table you add the highlighter and its colour parameters:
ColorHighlighter grayHighlighter = new ColorHighlighter(new IsCellEditablePredicate(table));
grayHighlighter.setBackground(Color.LIGHT_GRAY);
grayHighlighter.setForeground(table.getForeground());
grayHighlighter.setSelectedBackground(table.getSelectionBackground().darker());
grayHighlighter.setSelectedForeground(table.getSelectionForeground().darker());
table.setHighlighters(grayHighlighter);
This is the simplest way to color a particular Column or cell in a jTable.
First just create a simple class of CustomRenderer
class CustomRenderer extends DefaultTableCellRenderer <br />
{
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);
setForeground(Color.blue); >
return c;
}
}
This code gets the column of cell to render
TableColumn col = tblExamHistoryAll.getColumnModel().getColumn(5);
DefaultTableModel model3 = (DefaultTableModel)tblExamHistoryAll.getModel();
col.setCellRenderer(new CustomRenderer());
This is to clear all previous rows from your table. If you do not want them just remove these lines
model3.getDataVector().removeAllElements();
model3.fireTableDataChanged();
#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);
int control = row;
control = control % 2;
control = (control == 0) ? 1 : 0;
if (control == 1) {
c.setBackground(Color.green);
} else {
c.setBackground(Color.cyan);
}
return c;
}
The most straightforward way is to write a simple TableCellRenderer by extending the DefaultTableCellRenderer and overwriting the getTableCellRendererComponent method to setBackground( Color.RED ). For example:
final JTable table = new JTable(...);
table.setCellRenderer( new DefaultTableCellRenderer() {
public Component getTableCellRenderer(JTable table, Object value, ...) {
super.getTableCellRenderer(...);
if ( value should be highlighted ) {
setBackground( Color.RED );
}
return this;
}
});
You can extend DefaultTableCellRenderer, override getTableCellRendererComponent and call something like
if (myConditions) setBackground(myColor);
before returning "this" when conditions apply but it has a very annoying side-effect of changing the default back-color due to the way DefaultTableCellRenderer.setBackGround is coded.
The trick I found was to entirely duplicate the code of DefaultTableCellRenderer in a class named HackedDefaultTableCellRenderer, add a method that calls directly the Component's setBackground implementation:
public void setComponentBackground(Color c) {
super.setBackground(c);
}
then derive my customized rendered from this hacked class instead of from DefaultTableCellRenderer, and finally call setComponentBackground instead of setBackground in my customized getTableCellRendererComponent.
The drawback is that this HackedDefaultTableCellRenderer relies on a snapshot of DefaultTableCellRenderer.

Color Cell based on value

im using JXTable and trying to color the row based on value, BUT the show empty(but the render is running because it show the syso in console)
public class MyCellRenderer extends JLabel implements TableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int rowIndex, int vColIndex) {
SimpleTableModel mymodel = (SimpleTableModel) jxtableListar.getModel();
ModelProtocolo actualModel= (ModelProtocolo ) mymodel.getProtocolo(rowIndex) ;
if(actualModel.getValue() > 0) {
System.out.println("Yep the Render is working");
}
return this;
}
}
jxtableListar.setDefaultRenderer(Object.class, new MyCellRenderer ());
i did not found any usefull "tutorial" how to use the JXTable renderer, since they talk about something about Hightlight, but all the tutorials are "out of information" to learn
is there any good way/tutorial to color a JXTable row base on a value of the cell?
Your renderer is returning a JLabel (itself) that hasn't had anything set on it. Instead, extend DefaultTableCellRenderer:
public class MyCellRenderer extends DefaultTableCellRenderer {
#override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int rowIndex, int vColIndex) {
SimpleTableModel mymodel = (SimpleTableModel) jxtableListar.getModel();
ModelProtocolo actualModel= (ModelProtocolo ) mymodel.getProtocolo(rowIndex) ;
JLabel label = (JLabel) super.getTableCellRendererComponent(/* pass in all params */);
label.setText(/*whatever the text should be*/);
label.setBackground(/*whatever the color should be*/);
return label;
}
}

how to extend BooleanRenderer

I'm trying to implement mouse hover effects for my JTable.
(When the mouse goes over a table's row the row's background changes).
In order to do that, I extended the DefaultTableCellRenderer like this:
public class FileTableCellRenderer extends DefaultTableCellRenderer{
public FileTableCellRenderer() {
setOpaque(true);
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
FileTable fileTable = (FileTable)table;
Component c = super.getTableCellRendererComponent(fileTable, value, isSelected, hasFocus, row, column);
if(!isSelected){
if(row == fileTable.getCursorRow())
{
c.setBackground(Color.pink);
c.setForeground(Color.darkGray);
}
else
{
c.setBackground(Color.white);
c.setForeground(Color.darkGray);
}
}
this.setText(value.toString());
return this;
}
}
I set the JTable's defaultRenderer, and it works. The problem is I have one column which is Boolean. before I set my renderer I had this cute checkbox as default renderer for it.
Now, it just shows "true" or "false".
On the other hand, if I leave the defualt BooleanRenderer for the Boolean column, it will not be highlighted with the whole row...
I also tried to extned the JTable.BooleanRenderer, but it seems to be protected, so I cannot even extend it.
How can I leave this checkbox of the BooleanRenderer, but change background color with the rest of the row?
This cannot be done using inheritance since BooleanRenderer is a non-public inner class of JTable. But you can use composition instead. E.g., create a wrapper class that will accept a TableCellRenderer ('parent') as a constructor argument. If you pass a BooleanRenderer from your table as a parent, calling its getTableCellRendererComponent() method will return a Checkbox component, so you'll be able to make any further adjustments to it (I use code from the question to set the background color):
import javax.swing.*;
import javax.swing.plaf.UIResource;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
public class BooleanCellRenderer implements TableCellRenderer, UIResource {
private final TableCellRenderer parent;
public BooleanCellRenderer(TableCellRenderer parent) {
this.parent = parent;
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component c = parent.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
FileTable fileTable = (FileTable) table;
if (!isSelected) {
if (row == fileTable.getCursorRow()) {
c.setBackground(Color.pink);
c.setForeground(Color.darkGray);
} else {
c.setBackground(Color.white);
c.setForeground(Color.darkGray);
}
}
return c;
}
}
Then, in your main GUI class containing a JTable, take the table's default Boolean renderer and pass it to the wrapper:
FileTable fileTable = new FileTable();
fileTable.setDefaultRenderer(Boolean.class, new BooleanCellRenderer(fileTable.getDefaultRenderer(Boolean.class)));
You can leave the FileTableCellRenderer to render String cells:
FileTable fileTable = new FileTable();
fileTable.setDefaultRenderer(String.class, new FileTableCellRenderer());
fileTable.setDefaultRenderer(Boolean.class, new

TableModel Change the value of a jcheckbox cell after a second click in other checkbox

I have a table with a checkbox column, I am able to show the table like i want and I make editable just the column where the checkbox is placed. The problem is when I select the checkbox the render paint in the right way the checkbox but the value in the tablemodel isn't changed, this value just change until i give click in another checkbox, always the last checkbox that I choose doesn't reflects his value in the TableModel. The classes that I am using are:
Checkcell
class CheckCell extends DefaultCellEditor implements TableCellRenderer{
private JComponent component = new JCheckBox();
private boolean value = false;
public CheckCell() {
super(new JCheckBox());
}
#Override
public Object getCellEditorValue() {
return ((JCheckBox)component).isSelected();
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
( (JCheckBox) component).setBackground( new Color(200,200,0) );
boolean b = ((Boolean) value).booleanValue();
( (JCheckBox) component).setSelected( b );
( (JCheckBox) component).setHorizontalAlignment(SwingConstants.CENTER);
return ( (JCheckBox) component);
}
#Override
public boolean stopCellEditing() {
value = ((Boolean)getCellEditorValue()).booleanValue() ;
((JCheckBox)component).setSelected( value );
return super.stopCellEditing();
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value == null)
return null;
return ( (JCheckBox) component );
}
}
CheckRender
class CheckRender extends JCheckBox implements TableCellRenderer {
private JComponent component = new JCheckBox();
public CheckRender() {
setOpaque(true);
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
((JCheckBox) component).setBackground( new Color(0,200,0));
boolean b = ((Boolean) value).booleanValue();
((JCheckBox) component).setSelected(b);
((JCheckBox) component).setHorizontalAlignment(SwingConstants.CENTER);
return ((JCheckBox) component);
}
}
My Model
class DynaTableModel extends DefaultTableModel {
public DynaTableModel() {
super();
}
public DynaTableModel(final DynaTableBean dynaBean) {
super(dynaBean.getContent(), dynaBean.getHeaders());
}
#Override
public boolean isCellEditable(int row, int col) {
if (col == 0)
{
return true;
} else {
return false;
}
}
#Override
public void setValueAt(Object value, int row, int column) {
super.setValueAt(value, row, column);
}
Could you help me with this? what is missing me to change the value in the jtable when this change in the checkbox.
I am new in java and I think that there are something that is missing me.
Thanks in advanced.
Being a little more explicity, when I ticked the checkbox and I tried to recover the value from the TableModel the value is wrong by example if I ticked the first checkbox and I tried to recover the value using:
valor = (Boolean) tablemodel.getValueAt(i, 0);
I am getting false when this should be true, but if I check the first checkbox and later the second one the value of the first checkbox now is fine(true) but the second is still false is a kind of bug but I don't find the way to avoid this.
Someone knows how to avoid this.
I have a table with a checkbox column, I am able to show the table
like i want and I make editable just the column where the checkbox is
placed. The problem is when I select the checkbox the render paint in
the right way the checkbox but the value in the tablemodel isn't
changed, this value just change until i give click in another
checkbox, always the last checkbox that I choose doesn't reflects his
value in the TableModel
JTable has built in support for JCheckBox as TableCellRenderer and Editor
Boolean value represens JCheckBox in XxxTableModel, you would need to put there true or false (1st column)
override public Class getColumnClass(int c) {,

Categories

Resources