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.
Related
My JCheckBox "check all" header column works in that if I check the box, all checkboxes in this column become checked. I want to make it so that if you check the checkbox header so that all the boxes in the column become checked, uncheck one of the checkboxes in the column after will uncheck the checkbox header.
public class TablePanel extends javax.swing.JPanel {
public TablePanel() {
initComponents();
populateStringArrays(); //populate string arrays that will populate my table
table.setModel(tableModel);
table.getTableHeader().setReorderingAllowed(false);
setWidthOfTable();
loadTable(); //loads table with my array
table.getColumnModel().getColumn(5).setHeaderRenderer(new BoxRenderer(new MyItemListener()));
}
public class BoxRenderer extends JCheckBox implements TableCellRenderer, MouseListener{
String columnTitle = "Rings";
protected BoxRenderer rendererComponent;
int column;
boolean mousePressed = false;
public BoxRenderer(ItemListener listener){
rendererComponent = this;
rendererComponent.addItemListener(listener);
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if(table != null){
JTableHeader header = table.getTableHeader();
if(header != null){
rendererComponent.setForeground(header.getForeground());
rendererComponent.setBackground(header.getBackground());
rendererComponent.setFont(header.getFont());
Border border = header.getBorder();
header.setBorder(BorderFactory.createRaisedBevelBorder());
rendererComponent.setHorizontalTextPosition(SwingConstants.LEADING);
rendererComponent.setHorizontalAlignment(CENTER);
header.addMouseListener(rendererComponent);
}
}
setColumn(column);
rendererComponent.setText(columnTitle);
return rendererComponent;
}
protected void setColumn(int column) {
this.column = column;
}
public int getColumn() {
return column;
}
protected void handleClickEvent(MouseEvent e) {
if (mousePressed) {
mousePressed=false;
JTableHeader header = (JTableHeader)(e.getSource());
JTable tableView = header.getTable();
TableColumnModel columnModel = tableView.getColumnModel();
int viewColumn = columnModel.getColumnIndexAtX(e.getX());
int column = tableView.convertColumnIndexToModel(viewColumn);
if (viewColumn == this.column && e.getClickCount() == 1 && column != -1) {
doClick();
}
}
}
public void mouseClicked(MouseEvent e) {
((JTableHeader)e.getSource()).repaint();
}
public void mousePressed(MouseEvent e) {
mousePressed = true;
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
}
class MyItemListener implements ItemListener{
#Override
public void itemStateChanged(ItemEvent e) {
Object source = e.getSource();
if (source instanceof AbstractButton == false){
return;}
boolean checked = e.getStateChange() == ItemEvent.SELECTED;
System.out.println("Boolean checked = " + checked);
if(checked == true){
checkAll();
}else{
uncheckAll();
}
}
}
private void checkAll(){
for(int i=0; i<tableRecordArrayList.size(); i++){
table.getModel().setValueAt(true, i, 5);
}
}
private void uncheckAll(){
for(int i=0; i<tableRecordArrayList.size(); i++){
table.getModel().setValueAt(false, i, 5);
}
}
class TableModel extends javax.swing.table.AbstractTableModel{
/**Constructor**/
#Override
public int getRowCount() {
return tableRecordArrayList.size();
}
#Override
public int getColumnCount() {
return 6;
}
/**refresh for changes**/
public void refreshTable(){
fireTableDataChanged();
}
#Override
public Object getValueAt(int row, int column) {
TableRecord record = tableRecordArrayList.get(row);
switch(column){
case 0:
return record.firstName;
case 1:
return record.middleName;
case 2:
return record.lastName;
case 3:
return record.age;
case 4:
return record.height;
case 5:
return record.ring;
}
return "N/A";
}
#Override
public String getColumnName(int column){
/**set the title of the columns of the table**/
switch(column){
case 0:
return "First Name";
case 1:
return "Middle Name";
case 2:
return "Last Name";
case 3:
return "Age";
case 4:
return "Height(cm)";
case 5:
return "Has Championship Ring";
}
return "N/A";
}
/**turn column into checkboxes**/
#Override
public Class<?> getColumnClass(int column){
if(column == 5){
return Boolean.class;
}
return String.class;
}
#Override
public boolean isCellEditable(int row, int column){
return column == 5;
}
#Override
public void setValueAt(Object avalue, int row, int column){
TableRecord record;
Boolean v;
switch(column){
case 5:
record = tableRecordArrayList.get(row);
v = (Boolean) avalue;
record.ring = v;
fireTableCellUpdated(row,1);
printArrayList();
fireTableDataChanged();
break;
}
}
}
}
this question has been solved. Please visit this link to find the solution.
https://coderanch.com/t/700630/java/uncheck-JCheckBox-header-columns#3288215
I want to make it so that if you check the checkbox header so that all the boxes in the column become checked, uncheck one of the checkboxes in the column after will uncheck the checkbox header.
Add a TableModelListener to the TableModel.
When the TableModelEvent is generated you can check if the data was changed in your column containing the checkbox and then reset the header checkbox when required.
Check out: JTable -> TableModeListener for a basic example of using a TableModelListener.
I have a JTable that is used to capture user input which later will be printed upon hitting the Print button. I have an image that I would want to be the header and another one to be a footer.an image showing this can be found here. I have followed the example that I found from oracle documents here. I want it exactly the way it is done in TablePrintdemo3 here.
Allow me to post the classes here.
Here is my first class:
public class Product {
String productDescription;
Double productPrice;
//dummy properties
Integer productQuantity;
Double productTotalAmount;
public Product() {
this.productDescription = "";
this.productPrice = 0.0;
this.productTotalAmount = 0.0;
this.productQuantity = 0;
}//getters and setters here
}
The second class is a custom model as shown here:
public class ProductTableModel extends AbstractTableModel {
private final List<String> columnNames;
private final List<Product> products;
public ProductTableModel() {
String[] header = new String[] {
"Quantity",
"Description",
"Unity Price",
"Total Price"
};
this.columnNames = Arrays.asList(header);
this.products = new ArrayList<>();
}
#Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0: return Integer.class;
case 1: return String.class;
case 2: return Double.class;
case 3: return Double.class;
default: throw new ArrayIndexOutOfBoundsException(columnIndex);
}
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
Product product = this.getProduct(rowIndex);
switch (columnIndex) {
case 0: return product.getProductQuantity();
case 1: return product.getProductDescription();
case 2: return product.getProductPrice();
case 3: return product.getProductTotalAmount();
default: throw new ArrayIndexOutOfBoundsException(columnIndex);
}
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
#Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (columnIndex < 0 || columnIndex >= getColumnCount()) {
throw new ArrayIndexOutOfBoundsException(columnIndex);
} else {
Product product = this.getProduct(rowIndex);
switch (columnIndex) {
case 0: product.setProductQuantity((Integer)aValue); break;
case 1: product.setProductDescription((String)aValue); break;
case 2: product.setProductPrice((Double)aValue); break;
case 3: product.setProductTotalAmount((Double)aValue); break;
}
fireTableCellUpdated(rowIndex, columnIndex);
}
}
#Override
public int getRowCount() {
return this.products.size();
}
#Override
public int getColumnCount() {
return this.columnNames.size();
}
#Override
public String getColumnName(int columnIndex) {
return this.columnNames.get(columnIndex);
}
public void setColumnNames(List<String> columnNames) {
if (columnNames != null) {
this.columnNames.clear();
this.columnNames.addAll(columnNames);
fireTableStructureChanged();
}
}
public List<String> getColumnNames() {
return Collections.unmodifiableList(this.columnNames);
}
public void addProducts(Product product) {
int rowIndex = this.products.size();
this.products.add(product);
fireTableRowsInserted(rowIndex, rowIndex);
}
public void addProducts(List<Product> productList) {
if (!productList.isEmpty()) {
int firstRow = this.products.size();
this.products.addAll(productList);
int lastRow = this.products.size() - 1;
fireTableRowsInserted(firstRow, lastRow);
}
}
public void addEmptyRow(){
products.add(new Product());
this.fireTableRowsInserted(products.size()-1, products.size()-1);
}
public void insertProduct(Product product, int rowIndex) {
this.products.add(rowIndex, product);
fireTableRowsInserted(rowIndex, rowIndex);
}
public void deleteProduct(int rowIndex) {
if (this.products.remove(this.products.get(rowIndex))) {
fireTableRowsDeleted(rowIndex, rowIndex);
}
}
public Product getProduct(int rowIndex) {
return this.products.get(rowIndex);
}
public List<Product> getProducts() {
return Collections.unmodifiableList(this.products);
}
public void clearTableModelData() {
if (!this.products.isEmpty()) {
int lastRow = products.size() - 1;
this.products.clear();
fireTableRowsDeleted(0, lastRow);
}
}
}
The third class is my is as follows:
public class NiceTablePrinting extends MainClass{
#Override
protected JTable initializeTable(TableModel model) {
return new NicePrintingJTable(model);
}
private static class NicePrintingJTable extends JTable {
public NicePrintingJTable(TableModel model) {
super(model);
}
/**
* Overridden to return a fancier printable, that wraps the default.
* Ignores the given header and footer. Renders its own header.Always
* uses the page number as the footer.
*/
#Override
public Printable getPrintable(PrintMode printMode,
MessageFormat headerFormat,
MessageFormat footerFormat) {
MessageFormat pageNumber = new MessageFormat("- {0} -");
/* Fetch the default printable */
Printable delegate = per.getPrintable(printMode,null,pageNumber);
/* Return a fancy printable that wraps the default */
return new NicePrintable(delegate);
}
}
private static class NicePrintable implements Printable {
Printable delegate;
//
BufferedImage header;
BufferedImage footer;
//
boolean imagesLoaded;
{
try{
header=ImageIO.read(getClass().getResource("images/header.PNG"));
footer=ImageIO.read(getClass().getResource("images/footer.PNG"));
imagesLoaded=true;
}
catch(IOException ex)
{
ex.printStackTrace();
}
imagesLoaded=false;
}
public NicePrintable(Printable delegate) {
this.delegate = delegate;
}
#Override
public int print(Graphicsg,PageFormatpf,intpi)throwsPrinterException
{
if(!imagesLoaded){
return delegate.print(g, pf, pi);
}
//top origin
int x=(int)pf.getImageableX();
int y=(int)pf.getImageableY();
//
int iw=(int)pf.getImageableWidth();
int ih=(int)pf.getImageableHeight();
//image header
int hh= header.getHeight();
int hw=header.getWidth();
//image footer
int fh=footer.getHeight();
int fw=footer.getWidth();
int fY=ih-fh-10;
int fX=x;
//calculating the area to print the table
int tableX=10;
int tableY=hh +10;
int tableW=iw-20;
int tableH=ih-hh-10-fh-10;
/* create a new page format representing the shrunken area to print the table into */
PageFormat format = new PageFormat() {
#Override
public double getImageableX() {return tableX;}
#Override
public double getImageableY() {return tableY;}
#Override
public double getImageableWidth() {return tableW;}
#Override
public double getImageableHeight() {return tableH;}
};
/*
* We'll use a copy of the graphics to print the table to. This protects
* us against changes that the delegate printable could make to the graphics
* object.
*/
Graphics gCopy = g.create();
/* print the table into the shrunken area */
int retVal = delegate.print(gCopy, format, pi);
/* if there's no pages left, return */
if (retVal == NO_SUCH_PAGE) {
return retVal;
}
/* dispose of the graphics copy */
gCopy.dispose();
//draw the images
g.drawImage(header, x, y, hw, hh, null);
g.drawImage(footer, fX, fY, fw, fh, null);
return Printable.PAGE_EXISTS;
}
}
}
The fourth class is as follows:
public class MainClass {
private JTable table;
JFrame frame;
JButton print;
JScrollPane sp;
ProductTableModel model;
public MainClass(){
frame= new JFrame("Test Printing");
frame.setLayout(new java.awt.BorderLayout());
frame.setVisible(true);
///create table
model=new ProductTableModel();
table=this.initializeTable(model);
model.addEmptyRow();
table.setPreferredScrollableViewportSize(newjava.awt.Dimension(300,300));
sp= new javax.swing.JScrollPane(table);
frame.add(sp);
//button
print= new JButton("Print");
frame.add(print,BorderLayout.SOUTH);
frame.pack();
print.addActionListener((ActionEvent e) -> {
try {
printTable();
} catch (PrinterException ex) {
Logger.getLogger(MainClass.class.getName()).log(Level.SEVERE, null, ex);
}
});
}
protected JTable initializeTable(TableModel model) {
return new JTable(model);
}
public void printTable() throws PrinterException {
table.print(JTable.PrintMode.NORMAL, null, null, true, null, true);
}
public static void main(String [] args){
MainClass cl= new MainClass();
}
}
I would want to set my things the way it is done in TablePrintdemo3. Now I cannot see where I have gone wrong. Please assist.
The problem is it is printing only the table -no header and footer images.
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.
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 !
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.