I'm creating a JTable with data contained in 2 Vector, rowData and columnNames. I'm using a renderer to give the colour I want to the JTable. But data is invisible unless I click a cell: then only that cell data is visible.
My code:
// Creating table
final JTable tablaCurvas = new JTable();
// Applng colours and column sizes with renderer
TableCellRenderer tableRender = new TableRenderer();
tablaCurvas.setDefaultRenderer(Object.class, tableRender);
// Create an easy model to add data to table
tablaCurvas.setModel(new DefaultTableModel(rowData, columnNames){
private static final long serialVersionUID = 1L;
#Override
public boolean isCellEditable(int row, int column) {
//Only the second column
return column == 1;
}
});
// Necessary clicks to edit cell
((DefaultCellEditor) tablaCurvas.getDefaultEditor(Object.class)).setClickCountToStart(1);
// Add table into a scrollPane
JScrollPane scrollPane = new JScrollPane(tablaCurvas);
// Fill the pane
tablaCurvas.setFillsViewportHeight(true);
// Preferred size
tablaCurvas.setPreferredScrollableViewportSize(new Dimension(150,100));
And the renderer:
class TableRenderer extends DefaultTableCellRenderer
{
private static final long serialVersionUID = 1L;
public Component getTableCellRendererComponent(
JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column)
{
setEnabled(table == null || table.isEnabled());
if (column == 0)
setHorizontalAlignment(LEFT);
else // (column == 1)
setHorizontalAlignment(RIGHT);
for (int i=0; i<2; i++) {
TableColumn columna = table.getColumnModel().getColumn(i);
if (i==0){
columna.setPreferredWidth(150);
}
if (i==1) columna.setPreferredWidth(50);
}
setBackground(table.getBackground());
setForeground(table.getForeground());
if (row%2==1) setBackground(java.awt.Color.white);
else setBackground(new java.awt.Color(211, 217, 255));
return this;
}
Any way, appart from this, I'm finding much more difficult to learn how to use JTables than other Objects, because Oracle Tutorial is not very well explained in that chapter. Any book-chapter or online tutorial for JTables recommended?
You have to set the text for the DefaultTableCellRenderer component.
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
//.... your code
setText(value != null ? value.toString() : ""); // suppress null values
return this;
}
This screenshot was taken with some example data:
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.
I have implemented a JTree and populated some data. The table contains three columns and based on some values on a specific cell it should have either labels or combo boxes. All the values in the 3rd column are editable. I too have a JTree from which a node is selected and based on it the table values change accordingly. The issue exists when I edit a cell in the table and move to another node in the tree (which populates a new set of data in the table), the previously edited cell values exist in the table on top of the new cell values. Below is how I implemented TableCellRenderer and TableCellEditor. I might have used some concepts wrong since I am a beginner for swing. Please help me figure out what I have done incorrectly.
public void populateTableData(List<Field> list,JTree jTree){
fieldList = null;
tcBuilderTree = jTree;
fieldList = list;
md=new PropertiesTableModel(fieldList);
getPropertieseTable().setModel(md);
final TableCellRenderer cellRenderer = new TableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable arg0,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int col) {
if(value instanceof List<?>) {
List<Value> valueList=(ArrayList)value;
return createComboBox(valueList);
}
else{
JLabel lbl=new JLabel();
lbl.setText((String)value);
return lbl;
}
}
};
propertiesTable.setDefaultRenderer(Object.class, cellRenderer);
final TableCellEditor cellEditor = new TableCellEditor() {
private DefaultCellEditor textEditor;
private DefaultCellEditor currentEditor;
#Override
public Component getTableCellEditorComponent(JTable table,
Object value,
boolean isSelected,
int row,
int column) {
textEditor = new DefaultCellEditor(new JTextField());
PropertiesTableModel model = (PropertiesTableModel) table.getModel();
List<Value> values = model.getPossibleValues(row, column);
if (values != null) {
List<Value> valueList=(ArrayList)value;
currentEditor = new DefaultCellEditor(createComboBox(valueList));
} else {
currentEditor = textEditor;
}
return currentEditor.getTableCellEditorComponent(table, value,
isSelected, row, column);
}
#Override
public Object getCellEditorValue() {
return currentEditor.getCellEditorValue();
}
#Override
public boolean isCellEditable(EventObject anEvent) {
JTable tbl = (JTable) anEvent.getSource();
int row, col;
if (anEvent instanceof MouseEvent) {
MouseEvent evt = (MouseEvent) anEvent;
row = tbl.rowAtPoint(evt.getPoint());
col = tbl.columnAtPoint(evt.getPoint());
} else {
row = tbl.getSelectedRow();
col = tbl.getSelectedColumn();
}
if(col<2){
return false;
}
else
{
return true;
}
}
#Override
public boolean shouldSelectCell(EventObject anEvent) {
return true;
}
#Override
public boolean stopCellEditing() {
Object obj = currentEditor.getCellEditorValue();
fieldList.get(propertiesTable.getEditingRow())
.setDefaultValue(obj);
return currentEditor.stopCellEditing();
}
#Override
public void cancelCellEditing() {
currentEditor.cancelCellEditing();
}
#Override
public void addCellEditorListener(CellEditorListener l) {
}
#Override
public void removeCellEditorListener(CellEditorListener l) {
}
};
propertiesTable.setDefaultEditor(Object.class,cellEditor);
}
The issue exists when I edit a cell in the table and move to another node in the tree (which populates a new set of data in the table), the previously edited cell values exist in the table on top of the new cell values.
I would guess you are not stopping editing of the table cell before you reload the table with new data.
You probably should add the following to your code when you create the JTable:
JTable table = new JTable(...);
table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
See Table Stop Editing for more information.
The table contains three columns and based on some values on a specific cell it should have either labels or combo boxes
You may not need to create custom editors. Just have the table choose the appropriate default editor based on the cell being edited. You can do this by overriding the getCellEditor(...) method of the JTable. Check out: How to add unique JComboBoxes to a column in a JTable (Java) for an example of this approach.
I 'm a Java beginner.
I create an application with a JTable which is populated with a database.
In my database I have some 'news'. In my JTable I display titles of 'news' and when an user click on a row, it display a popup with the right contents of the news.
But I want to colorize the cell which are 'read' when the user clicked on it.
I use my own TableModel.
I hope I'm clear...
If I need to put some code, tell me what please...
public class JTableTest extends JFrame {
private JTable table;
private int col;
private int rowz;
/**
* Create the frame.
*/
public JTableTest() {
initComponents();
}
private void initComponents() {
/** any other components */
table = new JTable();//create the table
table.setDefaultRenderer(Object.class, new CustomModel());
table.addMouseListener(new CustomListener());
}
public class CustomListener extends MouseAdapter {
#Override
public void mouseClicked(MouseEvent arg0) {
super.mouseClicked(arg0);
//get the clicked cell's row and column
rowz = table.getSelectedRow();
col = table.getSelectedColumn();
// Repaints JTable
table.repaint();
}
}
public class CustomModel extends DefaultTableCellRenderer {
private static final long serialVersionUID = 1L;
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
Color c = Color.WHITE;//define the color you want
if (isSelected && row == rowz & column == col)
c = Color.GREEN;
label.setBackground(c);
return label;
}
}
}
Found this example of how to get the table cell on mouseClick: http://codeprogress.com/java/showSamples.php?index=52&key=JTableValueofSelectedCell
You can use this to get the selected row and column.
Then you need to create a custom TableCellRenderer, possibly as an inner class so that it can use the selected row and column data and set the background of the cell to your highlighted color
note: this code is not mine, I have taken it from another site and i'm simply trying to modify it.
I have a JTable with a load of details however, I want it so that when I change a particular cell for the first cell to change colour. Currently this code just highlights the row when I click on it, but I want it so that if I change one of the values to another number, the name cell for example to change red. I have tried a few things (if statements) but can't seem to work it. Any help would be great.
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
public class CustomCellRenderer{
JTable table;
TableColumn tcol;
public static void main(String[] args) {
new CustomCellRenderer();
}
public CustomCellRenderer(){
JFrame frame = new JFrame("Creating a Custom Cell Reanderer!");
JPanel panel = new JPanel();
String data[][] = {{"Vinod","Computer","3"},
{"Rahul","History","2"},
{"Manoj","Biology","4"},
{"Sanjay","PSD","5"}};
String col [] = {"Name","Course","Year"};
DefaultTableModel model = new DefaultTableModel(data,col);
table = new JTable(model);
tcol = table.getColumnModel().getColumn(0);
tcol.setCellRenderer(new CustomTableCellRenderer());
tcol = table.getColumnModel().getColumn(1);
tcol.setCellRenderer(new CustomTableCellRenderer());
tcol = table.getColumnModel().getColumn(2);
tcol.setCellRenderer(new CustomTableCellRenderer());
JTableHeader header = table.getTableHeader();
header.setBackground(Color.yellow);
JScrollPane pane = new JScrollPane(table);
panel.add(pane);
frame.add(panel);
frame.setSize(500,150);
frame.setUndecorated(true);
frame.getRootPane().setWindowDecorationStyle(JRootPane.PLAIN_DIALOG);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
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.green);
}
else {
if (row % 2 == 0) {
cell.setBackground(Color.lightGray);
}
else {
cell.setBackground(Color.lightGray);
}
}
return cell;
}
}
}
If you know row number you want to highlight just add in the end of the getTableCellRendererComponent method
if (row==theRowNumberToHighlight && column=0) {
cell.setForeground(Color.red);
}
Assuming your table model extends AbstractTableModel, extend TableModelListener. Use the following tableChanged method to figure out when to call your renderer:
public void tableChanged(TableModelEvent e)
{
if (e.getColumn() == columnYouAreChecking && e.getFirstRow() == rowYouAreChecking && e.getLastRow() == rowYouAreChecking)
{
// Change cell color here.
}
}
This code will get called every time the data in your table changes.
I want to put individual JComboBoxes into each cells of a JTable. ie. The JComboBox content is not identical for each cell.
I basically would like to be able to just call the following code to add a row of JComboBox into the JTable. Anyone has any idea? Thanks
JComboBox cb1 = new JComboBox(...);
JComboBox cb2 = new JComboBox(...);
model.addRow(new Object[] {"Row name", cb1, cb2} );
JComboBox cb3 = new JComboBox(...);
JComboBox cb4 = new JComboBox(...);
model.addRow(new Object[] {"Row name 2", cb3, cb4} );
The closest example code I can find is as follows. But it is for where JComboBox content is identical for the individual column. Not the solution I need.
TableColumn col = table.getColumnModel().getColumn(vColIndex);
col.setCellEditor(new MyComboBoxEditor(values));
where
public class MyComboBoxEditor extends DefaultCellEditor {
public MyComboBoxEditor(String[] items) {
super(new JComboBox(items));
}
}
Extend JTable with this code:
#Override
public TableCellEditor getCellEditor(int row, int column) {
Object value = super.getValueAt(row, column);
if(value != null) {
if(value instanceof JComboBox) {
return new DefaultCellEditor((JComboBox)value);
}
return getDefaultEditor(value.getClass());
}
return super.getCellEditor(row, column);
}
This will create a unique JComboBox cell editor for each combo box you get the a value for.
I am sure this will solve your problem. Mention in which column you need to set the combo box in .getColumn(int column)
private void addComboToTable(JComboBox combo) {
TableColumn gradeColumn = YourTable.getColumnModel().getColumn(0);
JComboBox comboBox = combo;
comboBox.removeAllItems();
try {
comboBox.addItem("Item 1");
comboBox.addItem("Item 2");
comboBox.addItem("Item 3");
} catch (NullPointerException e) {
} catch (Exception e) {
e.printStackTrace();
}
gradeColumn.setCellEditor(new DefaultCellEditor(comboBox));
}
You need to override:
Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
...in TableCellEditor. The value passed in to this method is what you can put in your JComboBox. That means that the 'value' for that particular cell needs to be something that can be translated into a collection. It could potentially just be a List of objects or it could be a POJO with fields that could be made into a JComboBox.
So just edit MyComboBoxEditor to override that method and change your model to allow for an Object that actually represents several other objects.
The JComboBox content is render identical for each row selection because
the JTable does not offer the capability to have more than one editor per column.
You have to extend the JTable class to support an additional selection for rows.
This article explains it very well:
http://www.javaworld.com/javaworld/javatips/jw-javatip102.html
In addition to cellEditor it is necessary to do the cellRenderer to paint the combobox in the cell, look at this:
public void example(){
TableColumn tmpColum =table.getColumnModel().getColumn(1);
String[] DATA = { "Data 1", "Data 2", "Data 3", "Data 4" };
JComboBox comboBox = new JComboBox(DATA);
DefaultCellEditor defaultCellEditor=new DefaultCellEditor(comboBox);
tmpColum.setCellEditor(defaultCellEditor);
tmpColum.setCellRenderer(new CheckBoxCellRenderer(comboBox));
table.repaint();
}
/**
Custom class for adding elements in the JComboBox.
*/
class CheckBoxCellRenderer implements TableCellRenderer {
JComboBox combo;
public CheckBoxCellRenderer(JComboBox comboBox) {
this.combo = new JComboBox();
for (int i=0; i<comboBox.getItemCount(); i++){
combo.addItem(comboBox.getItemAt(i));
}
}
public Component getTableCellRendererComponent(JTable jtable, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
combo.setSelectedItem(value);
return combo;
}
}
#Override
public TableCellEditor getCellEditor(int row, int column) {
Object value = super.getValueAt(row, column);
if(value != null) {
if(value instanceof JComboBox) {
return new DefaultCellEditor((JComboBox)value);
}
return getDefaultEditor(value.getClass());
}
return super.getCellEditor(row, column);
}
And then, override the toString method from JComboBox.
This page might help you, although it seems you are restricted to having the same combobox in all the cells in a column.
You need to create a subclass of JTable to override the method TableCellEditor getCellEditor(int row, int column).
This enables you to set arbitrary cell editors for any row and column combination. The default way is to set the cell editor for an entire column.
(You can also set individual cell renderers by overriding getCellRenderer.)
The easiest way is to implement your own TableModel
public class MyModel extends AbstractTableModel {
List rows;
public int getRowCount() {
return rows.size();
}
public int getColumnCount() {
return 4;
}
public Object getValueAt(int row, int column) {
return rows.get(row).getCol(col); //assuming your row "Object" has a getCol()
}
public Class<?> getColumnClass(int col) {
return Boolean.class;
}
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
rows.get(rowIndex).getCol(columnIndex).setValue(aValue);
}
}
Load this into you JTable. If you haven't replaced the default cell renderer for Boolean's, all you cells will be rendered as check boxes thanks to you implementation of getColumnClass(). All user input to these check boxes is collected with our setValueAt().