Attempting to create a custom JTable structure, I started with a very simple project to better understand. Unfortunately, as soon as I start to customize stuff, I get weird behaviours and I would like you to help me understand them. Thank you very much.
Here is my small project :
public class Tableau extends JFrame {
public Tableau() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800,600);
setContentPane(new Panel());
setVisible(true);
}
public static void main(String[] args) {
new Tableau();
}
private static class Panel extends JPanel {
private JTable table = new Table(4, 4);
public Panel() {
add(table);
}
}
private static class Table extends JTable {
private Renderer randerer = new Renderer();
public Table(int row, int col) {
super(new Model(row, col));
setAutoResizeMode(AUTO_RESIZE_OFF);
setDefaultRenderer(String.class, randerer);
setDefaultEditor(String.class, randerer);
}
private class Renderer implements TableCellRenderer, TableCellEditor {
String previousContent = "";
JTextPane rendererComponent = new JTextPane();
public Renderer() {
super();setOpaque(true);
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
rendererComponent.setText((String)value);
rendererComponent.setBorder(hasFocus ? BorderFactory.createLineBorder(Color.RED) : null);
rendererComponent.setBackground(isSelected ? Color.PINK : Color.GREEN);
FontMetrics fm = rendererComponent.getFontMetrics(rendererComponent.getFont());
if(((String)value).length()!=0) {rendererComponent.setPreferredSize(new Dimension(fm.stringWidth((String)value),fm.getHeight()));}
else {rendererComponent.setPreferredSize(new Dimension(20, fm.getHeight()));}
return rendererComponent;
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
rendererComponent.setText((String)value);
rendererComponent.setBackground(isSelected ? table.getSelectionBackground() : Color.MAGENTA);
if(isSelected) {rendererComponent.selectAll();}
previousContent = (String)value;
return rendererComponent;
}
#Override
public Object getCellEditorValue() {
return rendererComponent.getText();
}
#Override
public boolean isCellEditable(EventObject anEvent) {
return true;
}
#Override
public boolean shouldSelectCell(EventObject anEvent) {
return true;
}
#Override
public boolean stopCellEditing() {
fireEditingStoppedEvent();
return true;
}
#Override
public void cancelCellEditing() {
rendererComponent.setText(previousContent);
fireEditingCanceledEvent();
}
protected void fireEditingStoppedEvent() {
for(CellEditorListener l : listeners) {l.editingStopped(new ChangeEvent(this));}
}
protected void fireEditingCanceledEvent() {
for(CellEditorListener l : listeners) {l.editingCanceled(new ChangeEvent(this));}
}
private List<CellEditorListener> listeners = new LinkedList<CellEditorListener>();
#Override
public void addCellEditorListener(CellEditorListener l) {
listeners.add(l);
}
#Override
public void removeCellEditorListener(CellEditorListener l) {
listeners.remove(l);
}
}
}
private static class Model implements TableModel {
// private ColumnModel colonnes = new ColumnModel();
private List<List<Cellule>> colonnes = new LinkedList<List<Cellule>>();
private int rowCount = 0;
// private List<Cellule> cellules = new LinkedList<Cellule>();
private static class Cellule {
public Cellule() {}
public Cellule(Object content) {this.content = content;}
private Object content;
private Object getContent() {return content;}
private void setContent(Object newContent) {content = newContent;}
}
public Model(int row, int col) {
for(int j=0; j<col; j++) {
insertColumn(j);
}
for(int i=0; i<row; i++) {
insertRow(i);
}
}
#Override
public int getRowCount() {
return rowCount;
}
#Override
public int getColumnCount() {
return colonnes.size();
}
#Override
public String getColumnName(int columnIndex) {
String result = "";
for (; columnIndex >= 0; columnIndex = columnIndex / 26 - 1) {
result = (char)((char)(columnIndex%26)+'A') + result;
}
return result;
}
#Override
public Class<?> getColumnClass(int columnIndex) {
return colonnes.isEmpty() ? Object.class : getValueAt(columnIndex, 0).getClass();
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
return colonnes.get(columnIndex).get(rowIndex).getContent();
}
#Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
colonnes.get(columnIndex).get(rowIndex).setContent(aValue);
fireTableChanged(new TableModelEvent(this, rowIndex, rowIndex, columnIndex, TableModelEvent.UPDATE));
}
protected void fireTableChanged(TableModelEvent e) {
for(TableModelListener l : listeners) {
l.tableChanged(null);
}
}
public void insertColumn(int index) {
List<Cellule> newColumn = new LinkedList<Cellule>();
for(int i = 0; i<getRowCount(); i++) {
Cellule newCell = new Cellule("");
newColumn.add(newCell);
}
colonnes.add(index, newColumn);
fireTableChanged(new TableModelEvent(this, 0, getRowCount(), index, TableModelEvent.INSERT));
}
public void insertRow(int index) {
for(List<Cellule> colonne : colonnes) {
Cellule newCell = new Cellule("");
colonne.add(index, newCell);
}
rowCount++;
fireTableChanged(new TableModelEvent(this, index, index, TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT));
}
public void removeColumn(int index) {
colonnes.remove(index);
fireTableChanged(new TableModelEvent(this, 0, getRowCount(), index, TableModelEvent.DELETE));
}
public void removeRow(int index) {
for(List<Cellule> row : colonnes) {
row.remove(index);
}
rowCount--;
fireTableChanged(new TableModelEvent(this, index, index, TableModelEvent.ALL_COLUMNS, TableModelEvent.DELETE));
}
private List<TableModelListener> listeners = new LinkedList<TableModelListener>();
#Override
public void addTableModelListener(TableModelListener l) {
listeners.add(l);
}
#Override
public void removeTableModelListener(TableModelListener l) {
listeners.remove(l);
}
}
}
Basically, we have a JFrame (class Tableau), containing a JPanel (class Panel) containing a JTable (class Table). This Table uses a TableModel (class Model) and a JTextPane (class Renderer) that will serve for both rendering and editing the table content.
Here are my problems :
1) If I click a cell, it becomes white (which I don't understand how it is possible given the code of the renderer...). If I write something, first, nothing appears in the cell, but then, when I move the focus, the text appears...
2) If I click a cell and then move the focus using arrow keys, only then the selections seems to be done correctly. The red border is correctly displayed, etc. Why is the selection incorrect when I just click, without using arrows ?
Thanks !
Related
I have a jtable , a customtablemodel and a customcellrenderer with the NetBeans IDE.
I want to have different colors for different rows. But anytime I run the application ,
the rows are not painted as expected.
The code snippets are provided below.
This code is from the jtable :
duesTable = new javax.swing.JTable();
duesTable.setModel(duestableModel);
TableColumn tcol = duesTable.getColumnModel().getColumn(2);
tcol.setCellRenderer(new CustomTableCellRenderer2());
duesTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_OFF);
this code is from the TableCellRenderer
public class CustomTableCellRenderer2 extends DefaultTableCellRenderer{
#Override
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.green);
}
else {
cell.setBackground(Color.lightGray);
}
}
return cell;
}
}
This is from the Table Model.
public class DuesTableModel extends AbstractTableModel implements TableModelListener {
private List<List<Object>> dataList = new ArrayList<>();
private String[] header = { "ID"," PAYMENT YEAR" , "AMOUNT"}; // Payment year is a date
datatype
private int minRowCount = 5;
public DuesTableModel()
{ super(); }
public List<List<Object>> getDataList() {
return dataList;
}
public void setDataList(List<List<Object>> dataList) {
this.dataList = dataList;
fireTableDataChanged();
fireTableStructureChanged();
}
#Override
public int getRowCount() {
return Math.max(minRowCount, dataList.size());
}
#Override
public int getColumnCount() {
return header.length;
}
public void setHeader(String[] header) {
this.header = header;
}
public String[] getHeader() {
return header;
}
#Override
public void setValueAt(Object value, int row, int col)
{
int x = 0;
for(List<Object> l : dataList)
{
if(x == row)
{ l.set(col, value);}
x++;
}
fireTableCellUpdated(row,col);
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
Object value = null;
if(rowIndex < dataList.size())
{value = dataList.get(rowIndex).get(columnIndex);}
return value;
}
#Override
public String getColumnName(int col) {
return header[col];
}
#Override
public Class<?> getColumnClass(int column)
{
switch (column) {
case 0:
return Integer.class;
case 1:
return Date.class;
case 2:
return Double.class;
default:
return String.class;
}
}
#Override
public boolean isCellEditable(int row, int col) {
return true; //col != 1;
}
#Override
public void tableChanged(TableModelEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
Any suggestion to get the desired result.
I am trying to add image Icon in Jtable's cell. I have a code as mentioned below. What should I do for that?
package com.orb;
private final LinkedList<Product> list= new LinkedList<Product>();
private final LinkedList<Boolean> checkList = new LinkedList<Boolean>();
public void addItem(Product customer) {
list.add(customer);
checkList.add(false);
checkList.remove(true);
fireTableDataChanged();
}
#Override
public int getColumnCount() {
return 6;
}
#Override
public int getRowCount() {
return list.size();
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
Object obj = null;
if(columnIndex==4){
setTotal(list.get(rowIndex));
}
switch (columnIndex){
case 0: obj= list.get(rowIndex).getCode() ;break;
case 1: obj=list.get(rowIndex).getDescription(); break;
case 2: obj=list.get(rowIndex).getQuantity();break;
case 3: obj=list.get(rowIndex).getPrice();break;
case 4: obj=list.get(rowIndex).getTotal();break;
}
return obj;
}
#Override
public Class<?> getColumnClass(int arg0) {
switch(arg0){
case 0: case 1: return String.class;
case 2: return Integer.class;
case 3: case 4: return Double.class;
//case 5: return ImageIcon.class;
}
return super.getColumnClass(arg0);
}
#Override
public boolean isCellEditable(int arg0, int arg1) {
boolean isCellEditable = false;
switch(arg1){
case 2: case 3: isCellEditable= true;break;
default: isCellEditable= false;break;
}
return isCellEditable;
//return super.isCellEditable(arg0, arg1);
}
#Override
public void setValueAt(Object arg0, int arg1, int arg2) {
System.out.println("Value seted" +arg0 + arg1 + arg2);
switch(arg2){
case 0: break;
case 1: break;
case 2: list.get(arg1).setQuantity((Integer)arg0); setTotal(list.get(arg1)); break;
case 3: list.get(arg1).setPrice((Double)arg0); setTotal(list.get(arg1));break;
case 4: list.get(arg1).setTotal((Double)arg0);break;
//case 0: checkList.set(arg1, (Boolean)arg0);break;
default:break;
}
fireTableDataChanged();
}
public LinkedList<Product> getList() {
LinkedList<Product> temp = new LinkedList<Product>();
int index=-1;
for(Boolean isSelected:checkList){
index++;
if(isSelected){
temp.add(list.get(index));
}
}
return temp;
}
public void deleteRow(int rowNubmer)
{
list.remove(rowNubmer);
fireTableDataChanged();
}
public void setTotal(Product product){
Double total = 0.0d;
total = product.getQuantity ()* product.getPrice();
product.setTotal(total);
}
#Override
public void fireTableDataChanged() {
super.fireTableDataChanged();
}
I have a table model like above. I want to add image icon in table cell and want to delete cell when that icon is pressed. How can I do with this code?
Please give me full description over this.
You can use a DefaltTableCellRenderer which is backed by a JLabel which you can then use to set the icon.
The best solution would be to extend DefaltTableCellRenderer and override the getTableCellRendererComponent method and apply the icon as is needed on a cell by cell need
You can apply renderers either by defining the default renderer for a given Class type or directly to the column
Check out How to Use JTables and Using Custom Renderers in particular
UPDATED with example
This is A approach, there are many more...
public class TestTable {
public static void main(String[] args) {
new TestTable();
}
public TestTable() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JTable table = new JTable();
table.setGridColor(Color.LIGHT_GRAY);
table.setShowGrid(true);
table.setShowHorizontalLines(true);
table.setShowVerticalLines(true);
table.setModel(new TestTableModel());
table.getColumn("X").setCellRenderer(new DeleteCellRenderer());
table.getColumn("X").setCellEditor(new DeleteCellEditor());
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JScrollPane(table));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
protected class TestTableModel extends AbstractTableModel {
private List<RowData> rowData;
public TestTableModel() {
rowData = new ArrayList<RowData>(25);
for (int index = 0; index < 10; index++) {
rowData.add(new RowData(index));
}
}
#Override
public String getColumnName(int column) {
return column == 0 ? "Text" : "X";
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
RowData rd = rowData.get(rowIndex);
return rd.isDeletable();
}
#Override
public int getRowCount() {
return rowData.size();
}
#Override
public int getColumnCount() {
return 2;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
RowData rd = rowData.get(rowIndex);
return columnIndex == 0 ? rd.getText() : rd.isDeletable();
}
#Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
RowData rd = rowData.get(rowIndex);
if (columnIndex == 1) {
if (aValue instanceof Boolean && (Boolean)aValue) {
rowData.remove(rd);
fireTableRowsDeleted(rowIndex, rowIndex);
}
}
}
}
public class RowData {
private String text;
private boolean deletable;
public RowData(int row) {
text = "Row " + row;
deletable = Math.round(Math.random() * 1) == 0;
}
public String getText() {
return text;
}
public boolean isDeletable() {
return deletable;
}
}
public class DeleteCellRenderer extends DefaultTableCellRenderer {
public DeleteCellRenderer() {
try {
BufferedImage img = ImageIO.read(getClass().getResource("/Delete.png"));
setIcon(new ImageIcon(img));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
setText(null);
if (value instanceof Boolean && (Boolean)value) {
setEnabled(true);
} else {
setEnabled(false);
}
return this;
}
}
public class DeleteCellEditor extends AbstractCellEditor implements TableCellEditor {
private JLabel label;
public DeleteCellEditor() {
label = new JLabel("Delete");
}
#Override
public Object getCellEditorValue() {
return true;
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
stopCellEditing();
}
});
return label;
}
#Override
public boolean isCellEditable(EventObject e) {
return true;
}
}
}
Updated
Why not use a JButton/TableCellEditor? Here's why
This is done through the custom cell renderer that can extend JLabel. You can easily set the icon for JLabel.
Renderer is a component that must draw itself as a table cell after JTable calls getTableCellRendererComponent passing the cells state and content. It is common for a renderer then to set properties on its own and return this. The renderer can also return some other object as long as it extends Component.
I have Components I have created that are being put into a table model with two columns as below.
if (!newAcList.isEmpty()) {
for (Acronym acc : newAcList) {
tableModel.addRow(new String[]{acc.getName(), acc.getDefinition()});
}
}
What I need is when the user selects an item on the table model it converts the item back to my Acronym Object. I am using a Listselectionevent Listener.
Here is valueChanged selection event``
#Override
public void valueChanged(ListSelectionEvent e) {
String selectedAcData = null;
String selectDefData = null;
int[] selectedRow = accTable.getSelectedRows();
int[] selectedColumns = accTable.getSelectedColumns();
for (int i = 0; i < selectedRow.length; i++) {
// for (int j = 0; j < selectedColumns.length; j++) {
selectedAcData = (String) accTable.getValueAt(selectedRow[i], 0);
}
}
You might want to create a class that implements the TableModel interface for the acronyms. It might be called AcronymTableModel and is backed by a List<Acronym> list of Acronyms. Then give this model to your table.
The call to accTable.getValueAt(selectedRow[i], 0); in your valueChanged method will then return an instance of an Acronym.
Here's a quick example.
public class Example {
public static void main(String [] a) {
JFrame f = new JFrame();
JPanel p = new JPanel();
List<Acronym> acronyms = new ArrayList<Acronym>();
acronyms.add(new Acronym("FBI", "Federal Bureau of Investigation"));
acronyms.add(new Acronym("CIA", "Central Intelligence Agency"));
final TableModel tModel = new AcronymTableModel(acronyms);
JTable t = new JTable(tModel);
t.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
Acronym a = (Acronym)tModel.getValueAt(e.getFirstIndex(), 0);
System.out.println(a.acronym + ": " + a.definition);
}});
p.add(t);
f.getContentPane().add(p);
f.pack();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
class Acronym {
String acronym;
String definition;
public Acronym(String a, String d) {
acronym = a;
definition = d;
}
}
class AcronymTableModel implements TableModel {
private List<Acronym> acronyms;
public AcronymTableModel(List<Acronym> acs) {
this.acronyms = new ArrayList<Acronym>(acs);
}
#Override
public int getRowCount() {
return this.acronyms.size();
}
#Override
public int getColumnCount() {
return 2;
}
#Override
public String getColumnName(int columnIndex) {
switch(columnIndex) {
case 0:
return "Acronym";
case 1:
return "Definition";
}
return null;
}
#Override
public Class<?> getColumnClass(int columnIndex) {
return String.class; // Since both columns are simply
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
return acronyms.get(rowIndex);
}
#Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
}
#Override
public void addTableModelListener(TableModelListener l) {
}
#Override
public void removeTableModelListener(TableModelListener l) {
}
}
The Java tutorials are always good and have good examples.
http://docs.oracle.com/javase/tutorial/uiswing/events/listselectionlistener.html
I have a JTable with a custom TableCellRenderer and a custom TableCellEditor. By default, the first click on a table row switch from renderer to editor and the second click select the row.
Is there any way I can make the row selected on a single click (and swith to the editor)?
I have tried to use:
table.getSelectionModel().setSelectionInterval(row, row);
in my getTableCellEditorComponent but it doesn't work, and if I add it to my getTableCellRendererComponent it works, but only sometimes.
Here is a full example:
public class SelectRowDemo extends JFrame {
public SelectRowDemo() {
CellRendererAndEditor rendererAndEditor = new CellRendererAndEditor();
StringTableModel model = new StringTableModel();
JTable table = new JTable(model);
table.setDefaultEditor(String.class, rendererAndEditor);
table.setDefaultRenderer(String.class, rendererAndEditor);
model.addElement("");
model.addElement("");
model.addElement("");
add(new JScrollPane(table));
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Exception e) {
e.printStackTrace();
}
new SelectRowDemo();
}
});
}
class CellRendererAndEditor extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {
private final JLabel renderer = new JLabel();
private final JLabel editor = new JLabel();
#Override
public Object getCellEditorValue() {
return editor.getText();
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
String str = "renderer ";
str += (isSelected) ? "selected" : "not selected";
renderer.setText(str);
return renderer;
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
table.getSelectionModel().setSelectionInterval(row, row);
String str = "editor ";
str += (isSelected) ? "selected" : "not selected";
editor.setText(str);
return editor;
}
}
class StringTableModel extends AbstractTableModel {
private final List<String> data = new ArrayList<String>();
#Override
public int getColumnCount() {
return 1;
}
#Override
public int getRowCount() {
return data.size();
}
#Override
public Object getValueAt(int row, int column) {
return data.get(row);
}
#Override
public Class<?> getColumnClass(int column) {
return String.class;
}
#Override
public boolean isCellEditable(int row, int column) {
return true;
}
#Override
public void setValueAt(Object aValue, int row, int column) {
if(aValue instanceof String) {
data.set(row, (String)aValue);
fireTableRowsUpdated(row, column);
} else throw new IllegalStateException("aValue is not a String");
}
public void addElement(String s) {
data.add(s);
}
}
}
What's happening is that the table UI is starting to edit the cell before changing selection. If you put a println in getTableCellEditor() and shouldSelectCell(), the editor gets called first, with isSelected == false, then it calls shouldSelectCell and changes the selection.
You can see exactly where it happens in BasicTableUI.adjustSelection(MouseEvent).
boolean dragEnabled = table.getDragEnabled();
if (!dragEnabled && !isFileList && table.editCellAt(pressedRow, pressedCol, e)) {
setDispatchComponent(e);
repostEvent(e);
}
CellEditor editor = table.getCellEditor();
if (dragEnabled || editor == null || editor.shouldSelectCell(e)) {
table.changeSelection(pressedRow, pressedCol,
BasicGraphicsUtils.isMenuShortcutKeyDown(e),
e.isShiftDown());
}
As for rendering purposes, I'd just render it as if selected == true, since it will before that event is finished processing.
I want to gray non-editable cell in JTable.
I'm using such TableCellRenderer:
TableColumn column = table.getColumnModel().getColumn(0);
column.setCellRenderer(new GrayableCheckboxCellRenderer());
public class GrayableCheckboxCellRenderer extends JCheckBox implements TableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int vRowIndex, int vColIndex) {
boolean editable = isEditable(vRowIndex, vColIndex);
setBackground(editable ? UIManager.getColor("Label.background") : Color.LIGHT_GRAY);
setSelected((Boolean) value);
if (isSelected) {
// TODO: cell (and perhaps other cells) are selected, need to highlight it
}
return this;
}
// perfomance
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {}
public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {}
public void revalidate() {}
public void validate() {}
}
This works but with one annoying artefact:
Initially "checkbox" is "left-arranged", when I press left mouse button it moves to "center-arranged" and when I release mouse button it moves back to "left-arranged".
How to avoid such annoying artefact and probably there are better simpler solution for my problem?
Return an instance of GrayableCheckboxCellRenderer in a TableCellEditor.
Addendum: Aesthetically, you may want to condition the renderer's and editor's colors based on the defaults provided by the current Look & Feel, for example:
Color hilite = UIManager.getColor("Table.selectionBackground");
simpliest way by using preparedRenderer
import java.awt.*;
import java.util.Random;
import java.util.Vector;
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
public class Forum {
private JFrame frame = new JFrame("Frame");
private JPanel fatherCenter = new JPanel();
private JScrollPane tableScroll = new JScrollPane();
private myTableModel tableModel;
private JTable dialogTable;
private ListSelectionModel lsDialog;
private void addComponentsToPane(Container pane) {
tableModel = new myTableModel();
dialogTable = new JTable(tableModel) {
private static final long serialVersionUID = 1L;
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component comp = super.prepareRenderer(renderer, row, column);
JComponent jc = (JComponent) comp;//for Custom JComponent
if (!isRowSelected(row)) {
int modelRow = convertRowIndexToModel(row);
boolean type = (Boolean) getModel().getValueAt(modelRow, 2);
boolean type1 = (Boolean) getModel().getValueAt(modelRow, 3);
boolean type2 = (Boolean) getModel().isCellEditable(row, column);
comp.setForeground(Color.black);
if ((type) && (!type1)) {
comp.setBackground(Color.yellow);
} else if ((!type) && (type1)) {
comp.setBackground(Color.orange);
} else if ((!type) || (!type1)) {
comp.setBackground(Color.red);
//} else if ((!type2)) {
//comp.setForeground(Color.red);
//comp.setBackground(Color.magenta);
} else {
comp.setBackground(row % 2 == 0 ? getBackground() : getBackground().darker());
}
dialogTable.convertRowIndexToView(0);
} else {
comp.setForeground(Color.blue);
comp.setBackground(Color.lightGray);
}
if (!isCellEditable(row, column)) {
comp.setForeground(Color.red);
comp.setBackground(Color.magenta);
}
return comp;
}
};
tableScroll = new JScrollPane(dialogTable, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
tableScroll.setBorder(null);
dialogTable.getTableHeader().setReorderingAllowed(false);
dialogTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
lsDialog = dialogTable.getSelectionModel();
dialogTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
dialogTable.setRowHeight(20);
dialogTable.setRowMargin(2);
fatherCenter = new JPanel();
fatherCenter.setLayout(new BorderLayout(10, 10));
fatherCenter.add(tableScroll, BorderLayout.CENTER);
pane.add(fatherCenter);
}
private void addData() {
Runnable doRun1 = new Runnable() {
#Override
public void run() {
tableModel.resetTable();
Vector<String> tbl = new Vector<String>();
Vector<Object> tbl1 = new Vector<Object>();
Random rnd = new Random();
tbl.add("Integer");
tbl.add("Double");
tbl.add("Boolean");
tbl.add("Boolean");
tbl.add("String");
tableModel.setColumnNames(tbl);
for (int row = 0; row < 30; row++) {
tbl1 = null;
tbl1 = new Vector<Object>();
tbl1.addElement(row + 1);
tbl1.addElement(rnd.nextInt(25) + 3.14);
tbl1.addElement((row % 3 == 0) ? false : true);
tbl1.addElement((row % 5 == 0) ? false : true);
if (row % 7 == 0) {
tbl1.add(("Canc"));
} else if (row % 6 == 0) {
tbl1.add(("Del"));
} else {
tbl1.add(("New"));
}
tableModel.addRow(tbl1);
}
addTableListener();
}
};
SwingUtilities.invokeLater(doRun1);
}
private void addTableListener() {
tableModel.addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent tme) {
if (tme.getType() == TableModelEvent.UPDATE) {
System.out.println("Cell " + tme.getFirstRow() + ", "
+ tme.getColumn() + " changed. The new value: "
+ tableModel.getValueAt(tme.getFirstRow(),
tme.getColumn()));
}
}
});
}
private void createAndShowGUI() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout(10, 10));
addComponentsToPane(frame.getContentPane());
addData();
frame.setLocation(150, 150);
frame.setPreferredSize(new Dimension(400, 646));
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
Forum osFrame = new Forum();
}
public Forum() {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
private class myTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private Vector<Vector<Object>> data;
private Vector<String> colNames;
private boolean[] _columnsVisible = {true, true, true, true, true};
myTableModel() {
this.colNames = new Vector<String>();
this.data = new Vector<Vector<Object>>();
}
myTableModel(Vector<String> colnames) {
this.colNames = colnames;
this.data = new Vector<Vector<Object>>();
}
public void resetTable() {
this.colNames.removeAllElements();
this.data.removeAllElements();
}
public void setColumnNames(Vector<String> colNames) {
this.colNames = colNames;
this.fireTableStructureChanged();
}
public void addRow(Vector<Object> data) {
this.data.add(data);
this.fireTableDataChanged();
this.fireTableStructureChanged();
}
public void removeRowAt(int row) {
this.data.removeElementAt(row);
this.fireTableDataChanged();
}
#Override
public int getColumnCount() {
return this.colNames.size();
}
#Override
public Class<?> getColumnClass(int colNum) {
switch (colNum) {
case 0:
return Integer.class;
case 1:
return Double.class;
case 2:
return Boolean.class;
case 3:
return Boolean.class;
default:
return String.class;
}
}
#Override
public boolean isCellEditable(int row, int colNum) {
switch (colNum) {
case 2:
return false;
default:
return true;
}
}
#Override
public String getColumnName(int colNum) {
return this.colNames.get(colNum);
}
#Override
public int getRowCount() {
return this.data.size();
}
#Override
public Object getValueAt(int row, int col) {
Vector<Object> value = this.data.get(row);
return value.get(col);
}
#Override
public void setValueAt(Object newVal, int row, int col) {
Vector<Object> aRow = data.elementAt(row);
aRow.remove(col);
aRow.insertElementAt(newVal, col);
fireTableCellUpdated(row, col);
}
public void setColumnVisible(int index, boolean visible) {
this._columnsVisible[index] = visible;
this.fireTableStructureChanged();
}
}
}
Just explicitly setting the alignment in the 'getTableCellRendererComponent()' method solves the problem. Add the below line before returning from the method.
setHorizontalAlignment(SwingConstants.CENTER);