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
Related
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.
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;
}
}
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
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)
I need to display an image in one of jTable cells.
I wrote this:
class ImageRenderer extends DefaultTableCellRenderer {
JLabel lbl = new JLabel();
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
lbl.setText((String) value);
lbl.setIcon(new ImageIcon("/home/ariyan/Desktop/71290452.jpg"));
return lbl;
}
}
and then used it as this:
jTable1.getColumn(0).setCellRenderer(new ImageRenderer());
But this didn't work
How I can do that?
Thanks
JTable already provides a default renderer for images. You just need to tell the table what type of data is contained in each column and it will choose the best renderer:
a) override the getColumnClass() method of the JTable or the TableModel to return the class of data in the column. In this case you should return an Icon.class.
b) add an ImageIcon to the table model.
Now the JTable will use the default Icon renderer for that column.
Hmm: jTable1.getColumnModel().getColumn(0).setCellRenderer(new ImageRenderer()); perhaps?
Here's the relevant extract of some quick test code I put together to quickly verify my guess. It displays icons from a folder (it assumes all files in a folder are icons, so you should test it with something like an XDG icon theme sub directory). Install table model first then add the cell renderer on the columns:
class Renderer extends DefaultTableCellRenderer {
#Override
public Component getTableCellRendererComponent (JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row, int column) {
if(isSelected) {
this.setBackground(table.getSelectionBackground());
this.setForeground(table.getSelectionForeground());
}
else {
this.setBackground(table.getBackground());
this.setForeground(table.getForeground());
}
if(column == 0) {
this.setText(list[row]);
}
else {
// edit as appropriate for your icon theme
this.setIcon(new ImageIcon("/usr/share/icons/default.kde4/16x16/apps/"+list[row]));
}
return this;
}
}
class Model extends DefaultTableModel {
#Override
public boolean isCellEditable (int row, int column) {
return false;
}
#Override
public Object getValueAt (int row, int column) {
return list[row];
}
#Override
public int getRowCount () {
return list.length;
}
#Override
public int getColumnCount () {
return 2;
}
#Override
public String getColumnName (int column) {
return column == 0? "Name" : "Preview";
}
#Override
public Class<?> getColumnClass (int columnIndex) {
return String.class;
}
}
// edit base directory as appropriate for your icon theme of choice
static String[] list=new File("/usr/share/icons/default.kde4/16x16/apps/").list();