I am looking to modify the way cell input is handled in my JTable. Currently I am using a DefaultTableModel as seen below.
DefaultTableModel model = new DefaultTableModel() {
#Override
public boolean isCellEditable(int row, int col) {
return col == 1 || col == 2 || col == 6;
}
#Override
public Class getColumnClass(int col) {
if (col == 6) {
return Integer.class;
} else {
return String.class;
}
}
};
With this code column 6 forces the user to input an Integer. I would like to take this further by not allowing the number to be outside of a range (e.g. 1-100) and also for the field to never be empty (The column will have data in it prior to user interaction). I have read the docummentation but cannot seem to find anything that manages the behaviour of column types. Thanks!
You would need to create a custom editor.
The following example demonstrates and editor that forces the data to be 5 characters:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
public class TableFiveCharacterEditor extends DefaultCellEditor
{
private long lastTime = System.currentTimeMillis();
public TableFiveCharacterEditor()
{
super( new JTextField() );
}
public boolean stopCellEditing()
{
JTable table = (JTable)getComponent().getParent();
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(
table,
"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;
}
private static void createAndShowUI()
{
JTable table = new JTable(5, 5);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane(table);
// Use a custom editor
TableCellEditor fce = new TableFiveCharacterEditor();
table.setDefaultEditor(Object.class, fce);
JFrame frame = new JFrame("Table Five Character Editor");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( scrollPane );
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
You would need to modify the editor to make sure:
the data is an Integer by using the Integer.parseInt(...) method
that the Integer value is in your desired range
Edit:
how can I apply this to influence one column rather than the entire table.
You can add the editor to the TableColumn:
table.getColumnModel().getColumn(...).setCellEditor(...);
Overriding the behaviour of the DefaultCellEditor achieves the desired outcome.
DefaultCellEditor editor = new DefaultCellEditor(new JTextField()) {
#Override
public boolean stopCellEditing() {
JTable table = (JTable) getComponent().getParent();
try {
String value = (String) getCellEditorValue();
if (Integer.parseInt(value) < 1) {
JTextField textField = (JTextField) getComponent();
textField.setBorder(new LineBorder(Color.red));
textField.selectAll();
textField.requestFocusInWindow();
return false;
}
} catch (NumberFormatException ex) {
return false;
}
return super.stopCellEditing();
}
};
Then added to the desired column of the table.
table.getColumnModel().getColumn(6).setCellEditor(editor);
Edit: The behaviour inside the if statement will not occur if a NumberFormatException is thrown, you may want to put the same lines of code within the catch.
Related
I would like to know how to set up a JComboBox in a particular cell in a JTable.
I have seen people using TableColumn setCellEditor(new DefaultCellEditor(comboBox)).
But this is for an entire column, I would like a specific cell.
So maybe I should do a custom TableCellEditor that would fit my needs, but I am a little lost on how to do it...
The goal of this is to manage filters on parameters. There are two kinds of filters:
The one that compares two values, for instance: number of balloons > 5
The one that will say is a value is inside a range of value, for instance: parameter name is inside {"one", "two", "three", "seven"}.
screenshot of my JTable:
As we can see in the picture, when there is the "comparator" "is among", we would need a JComboBox in cell[0][2] to choose the values of the range within a complete set of fields.
While cell[1][2] does not need a JComboBox, but just an editable cell.
I hope I have been clear and thank you for your help.
EDIT:
I was able to display a JComboBox only to realize, I couldn't select multiple values on it. So now I am trying to display a JList instead of a ComboBox.
But when I click on the cell, the JList is not displayed, I don't know why.
Here is my code:
JTable tableParametersFilter = new JTable(modelParametersFilter){
// Determine editor to be used by row
public TableCellEditor getCellEditor(int row, int column)
{
int modelColumn = convertColumnIndexToModel( column );
int modelRow = convertRowIndexToModel( row );
Parameter_Filter pf = view.listParameter_Filter.get(modelRow);
if(modelColumn == 2 && pf instanceof Parameter_Filter_To_List_Of_Fields) {
Parameter_Filter_To_List_Of_Fields pftlof = (Parameter_Filter_To_List_Of_Fields)pf;
JList<String> list = new JList<String>(pftlof.list_of_fields_total_names);
list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION );
list.setLayoutOrientation(JList.VERTICAL_WRAP);
list.setVisibleRowCount(-1);
return new TableCellEditor() {
#Override
public boolean stopCellEditing() {
return false;
}
#Override
public boolean shouldSelectCell(EventObject anEvent) {
return false;
}
#Override
public void removeCellEditorListener(CellEditorListener l) {
}
#Override
public boolean isCellEditable(EventObject anEvent) {
return true;
}
#Override
public Object getCellEditorValue() {
return list.getSelectedValuesList().toString();
}
#Override
public void cancelCellEditing() {
}
#Override
public void addCellEditorListener(CellEditorListener l) {
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
return list;
}
};
}
return super.getCellEditor(row, column);
}
};
Any suggestions?
I have solved my problem.
I have not been able to add multiple choice JComboBox, or a displayable JList on the Cell of the Jtable.
Instead, I have used a JOptionPane that displayed a JList.
Here's the code:
tableParametersFilter.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
JTable target = (JTable)e.getSource();
int row = target.getSelectedRow();
int column = target.getSelectedColumn();
if(column == 2){
Parameter_Filter pf = view.listParameter_Filter.get(row);
if(pf instanceof Parameter_Filter_To_List_Of_Fields) {
Parameter_Filter_To_List_Of_Fields pftlof = (Parameter_Filter_To_List_Of_Fields) pf;
JList<String> jlist = new JList<String>(pftlof.list_of_fields_total_names);
String StringOfIntArray = (String) tableParametersFilter.getValueAt( row, 2);
int[] list_parameter_id = Statique.StringOfIntArrayToIntegerArray(StringOfIntArray);
if(list_parameter_id.length < jlist.getModel().getSize()) {
int[] list_places = pftlof.getPlaceOfParameters(list_parameter_id);
for(int i = 0; i < list_places.length; i++) {
jlist.setSelectedIndices(list_places);
}
}
JScrollPane scrollPane = new JScrollPane(jlist);
scrollPane.setPreferredSize( new Dimension( 500, 500 ) );
JOptionPane.showMessageDialog(
null, scrollPane, "Multi-Select Example", JOptionPane.PLAIN_MESSAGE);
int[] SelectedIndices = jlist.getSelectedIndices();
Integer[] listParametersId = new Integer[SelectedIndices.length];
for(int i = 0; i < SelectedIndices.length; i++) {
int id = pftlof.list_of_fields_Total[SelectedIndices[i]].id;
try {
Parameter p = Parameter.getParameter(
id,
Parameter_Filter_To_List_Of_Fields.getTotal_Parameter_In_Parameter_Filter_To_List_Of_Fields());
listParametersId[i] = p.id;
} catch (NoSuchFieldException e1) {
e1.printStackTrace();
}
}
System.out.println(Arrays.toString(listParametersId));
tableParametersFilter.setValueAt(Arrays.toString(listParametersId), row, 2);
}
}
}
}
I am trying to change the color of some cells in my JTable. I have tried to override getTableCellRendererComponent in a simple example, and it works nice. But when I do the same in my project nothing changes...
I have my JPanel with my JTable in a Box like this:
boxTable=Box.createHorizontalBox();
box2Table.add(boxTable);
//JTable
tablaContador = new JTable(datosContador,cabeceraContador);
//MODIF COLOR
tablaContador.setDefaultRenderer(Object.class, new ColorRenderer());
Doing:
System.out.println(tablaContador.getColumnClass(3));
I can know that the first parameter of setDefaultRenderer is Object.class
I don't know if the problem is here... i have only strings in the Table, but I have tried String.class and nothing happens
Then I modify some things of JTable's Cells:
tablaContador.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
boxTable.add(tablaContador);
//Align cells
for (int i=0; i<cabeceraContador.length;i++){
tablaContador.getColumnModel().getColumn(i).setCellRenderer(alinearCeldas);
}
//Modify cells' width
tablaContador.getColumnModel().getColumn(0).setMinWidth(150);
for (int i=1; i<cabeceraContador.length;i++){
tablaContador.getColumnModel().getColumn(i).setMaxWidth(40);
}
//Scroll for the Table
scrollContador=new JScrollPane(tablaContador,JScrollPane.VERTICAL_SCROLLBAR_NEVER,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollContador.setPreferredSize(new Dimension(1000,80));
scrollContador.setMinimumSize(new Dimension(1000,80));
scrollContador.setMaximumSize(new Dimension(2000,80));
//Add scroll to the box
box2Table.add(scrollContador);
And my ColorRenderer class is:
public class ColorRenderer extends DefaultTableCellRenderer{
private Component c;
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,int row, int column) {
c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
c.setBackground(Color.BLUE);
return c;
}
}
Table result
So It does not work in my project i don't know why
any idea?
thaks!
I see:
tablaContador.setDefaultRenderer(Object.class, new ColorRenderer());
and then I see:
for (int i=0; i<cabeceraContador.length;i++)
{
tablaContador.getColumnModel().getColumn(i).setCellRenderer(alinearCeldas);
}
The assignment of the renderer to a specific column takes precedence over setting the default renderer so your color renderer is never used.
Not exactly what you are trying to do, but I would guess you need to add the color rendering logic to the alignment renderer. In other words all the rendering logic must be contained in a single renderer. You can't merge multiple renderers.
Here is a simple example of a custom renderer:
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
public class TableRenderer extends JPanel
{
public TableRenderer()
{
String[] columnNames = {"String", "Integer"};
Object[][] data =
{
{"A", new Integer(1)},
{"B", new Integer(2)},
{"C", new Integer(10)},
{"D", new Integer(4)}
};
DefaultTableModel model = new DefaultTableModel(data, columnNames);
JTable table = new JTable( model );
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane( table );
add( scrollPane );
// Override default renderer on a specific column
TableCellRenderer colorRenderer = new ColorRenderer();
table.getColumnModel().getColumn(1).setCellRenderer( colorRenderer );
}
/*
** Color the focused cell
*/
class ColorRenderer extends DefaultTableCellRenderer
{
public ColorRenderer()
{
super();
setHorizontalAlignment(JLabel.RIGHT);
}
#Override
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (isSelected)
setBackground( table.getSelectionBackground() );
else
{
setBackground( null );
try
{
int number = Integer.parseInt( value.toString() );
if (number > 9)
setBackground( Color.RED );
}
catch(Exception e) {}
}
return this;
}
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("Color Renderer");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TableRenderer());
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}
I have celltable with 4 column (name size addedBy modifiedBy )
all the value is filled during the run time.
The table actully show the documents.
Documents can be pdf, txt , doc so
i want to add icon before the name of the document.
and i also want one more Image column before name column
My code so far.
*
private CellTable<FDocument> getDocumentTable() {
if (documentTable == null) {
documentTable = new CellTable<FDocument>();
documentTable.setSize("600px", "300px");
documentTable.addColumn(nameColumnD, "NAME");
documentTable.addColumn(sizeColumnD, "SIZE");
documentTable.addColumn(modified_by_ColumnD, "MODIFIED BY");
documentTable.addColumn(dateColumnD, "MODIFIED ON");
}
return documentTable;
}
TextColumn<FDocument> idColumnD = new TextColumn<FDocument>() {
#Override
public String getValue(FDocumentobject) {
// TODO Auto-generated method stub
return object.getId();
}
};
TextColumn<FDocument> nameColumnD = new TextColumn<FDocument>() {
#Override
public String getValue(FDocumentobject) {
return object.getName();
}
};
TextColumn<FDocument> sizeColumnD = new TextColumn<FDocument>() {
#Override
public String getValue(FDocumentobject) {
return object.getSize();
}
};
TextColumn<FDocument> modified_by_ColumnD = new TextColumn<FDocument>() {
#Override
public String getValue(FilenetDocument object) {
return object.getModifiedBy();
}
};
TextColumn<FDocument> dateColumnD = new TextColumn<FDocument>(){
#Override
public String getValue(FDocumentobject){
return object.getModifiedOn();
}
};
private void addValuesToTable(){
List<FDocument> FDC = null;
/*
* Adding data to folder Table
*/
ArrayList<FDocument> documentsArrayList = new ArrayList<FDocument>();
Iterator<String> iteratorDocument = documents.getDocuments().getDocumentCollection().keySet().iterator();
while(iteratorDocument.hasNext()){
String key = iteratorDocument.next().toString();
FDocument value = documents.getDocuments().getDocumentCollection().get(key);
documentsArrayList.add(new FDocument(value.getName(), value.getSize(),value.getModifiedBy(), value.getModifiedOn(),value.getId()));
}
FDC = documentsArrayList;
// Create a data provider.
ListDataProvider<FDocument> dataProvider1 = new ListDataProvider<FDocument>();
// Connect the table to the data provider.
dataProvider1.addDataDisplay(documentTable);
// Add the data to the data provider, which automatically pushes it to the widget.
List<FDocument> listDocument = dataProvider1.getList();
for (FDocument fDocument: FDC) {
listDocument.add(fDocument1);
}
This the way i have made my table and the value.
Plz any one tell me the procedure
to add icon before the name of the document.
and i also want one more Image column before name column
Use DefaultTableCellRenderer to set custom renderer against the column with the desired icon. As shown below, the renderer creates a new label to mask all the cells within the selected column.
private class CellRenderer extends DefaultTableCellRenderer
{
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
JLabel label = new JLabel((String)value);
label.setOpaque(true);
Icon icon = new ImageIcon("icon.png");
label.setIcon(icon);
return label;
}
}
And then apply it to your table as shown below:
table.getColumnModel().getColumn(0).setCellRenderer(new CellRenderer());
Edited:
If you're using GWT then see here for an example code for Grid Cell format.
For creating image column, You need to define a custom renderer that sets the icon on the label
import java.awt.Component;
import javax.swing.ImageIcon;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
public class MyRenderer extends DefaultTableCellRenderer {
/*
* #see TableCellRenderer#getTableCellRendererComponent(JTable, Object, boolean, boolean, int, int)
*/
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int column) {
ImageIcon icon = new ImageIcon(getClass().getResource("images/moon.gif"));
setText((String)value);
setIcon(icon);
return this;
}
}
And then, use the renderer in a table as follows,
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
public class Sample {
public static void main(String[] args) {
JFrame f = new JFrame("Sample");
f.getContentPane().setLayout(new GridLayout(1,0,0,0));
TableModel model = new AbstractTableModel() {
public Object getValueAt(int rowIndex, int columnIndex) {
return rowIndex + "," + columnIndex;
}
public int getColumnCount() {
return 3;
}
public int getRowCount() {
return 10;
}
};
JTable table = new JTable(model);
table.getColumnModel().getColumn(1).setCellRenderer(new MyRenderer());
JScrollPane pane = new JScrollPane(table);
f.getContentPane().add(pane);
f.pack();
f.setVisible(true);
}
}
Both of these will probably need a custom TableCellRenderer...
Refer to the API docs here... http://docs.oracle.com/javase/1.4.2/docs/api/javax/swing/table/DefaultTableCellRenderer.html
You basically want to overwrite the getTableCellRendererComponent() method, and add in any additional code for rendering the image.
For example, to add an icon before the document, you would do the following...
public void MyTableCellRenderer extends DefaultTableCellRenderer {
public MyTableCellRenderer(){
super();
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column){
Component renderer = super.getTableCellRendererComponent(table,value,isSelected,hasFocus,row,column);
if (row == 0 && renderer instanceof JLabel){ // where row == 0 is the row you want to add the icon to
((JLabel)renderer).setIcon(new ImageIcon("image.png"));
}
return renderer;
}
}
You would need to set this as the TableCellRenderer for the column or table.
You would also do a similar thing for adding an image column to the table.
I have a JTable displaying rows from an SQL database. The table is relatively small (only 4 columns and up to 1000 rows).
I would like to give the user the opportunity to edit any cells in the table but want to avoid restricting it so much so that they must use an edit dialog box (this makes for far easier error checking and validation but is less intuitive)
I have tried a few different ways of controlling edit selections using the valueChanged method of my JTable but haven't had much luck.
I would like each row to be edited and written to the database at the conclusion of editing. I would like that once a cell has been clicked to start the editing of that row, no other rows can be selected until the user has finished editing the row (other rows are grayed out). After editing each cell and pressing enter, the edit selection should jump to the next column in the same row.
Can anyone give pointers on how I can achieve this?
// Create table with database data
table = new JTable(new DefaultTableModel(data, columnNames)) {
public Class getColumnClass(int column) {
for (int row = 0; row < getRowCount(); row++) {
Object o = getValueAt(row, column);
if (o != null){
return o.getClass();
}
}
return Object.class;
}
#Override
public boolean isCellEditable(int row, int col){
return true;
}
#Override
public boolean editCellAt(int row, int column) {
boolean ans = super.editCellAt(row, column);
if (ans) {
Component editor = table.getEditorComponent();
editor.requestFocusInWindow();
}
return ans;
}
#Override
public void valueChanged(ListSelectionEvent source) {
super.valueChanged(source);
if (table!=null)
table.changeSelection(getSelectedRow(), getSelectedColumn()+1, false, false);
}
};
Edit - custom cell editor with table pointer seems to be a start
public class ExchangeTableCellEditor extends AbstractCellEditor implements TableCellEditor {
private JTable table;
JComponent component = new JTextField();
public ExchangeTableCellEditor(JTable table) {
this.table = table;
}
public boolean stopCellEditing() {
boolean ans = super.stopCellEditing();
//now we want to increment the cell count
table.editCellAt(table.getSelectedRow(), table.getSelectedColumn()+1);
return ans;
}
#Override
public void cancelCellEditing() {
//do nothing... must accept cell changes
}
#Override
public Object getCellEditorValue() {
return ((JTextField)component).getText();
}
#Override
public Component getTableCellEditorComponent(JTable arg0, Object value,
boolean arg2, int arg3, int arg4) {
((JTextField)component).setText((String)value);
return component;
}
}
The default renderer and editor is typically adequate for most data types, but you can define custom renderers and editors as needed.
Addendum: I'm unfamiliar with the approach shown in your fragment. Instead, register a TableModelListener with your model, as shown below, and update the database with whatever granularity is warranted. See also How to Use Tables: Listening for Data Changes.
Addendum: #kleopatra is correct about your TableCellEditor. One convenient way to notify listeners is to invoke the super implementation, as shown here. Note that the delegate invokes fireEditingStopped().
/** #see https://stackoverflow.com/questions/9155596 */
public class NewJavaGUI extends JPanel {
private final JTable table;
public NewJavaGUI() {
String[] colNames = {"C1", "C2", "C3"};
DefaultTableModel model = new DefaultTableModel(colNames, 0) {
#Override
public boolean isCellEditable(int row, int col) {
// return your actual criteria
return true;
}
#Override
public Class getColumnClass(int col) {
// return your actual type tokens
return getValueAt(0, col).getClass();
}
};
// Add data; note auto-boxing
model.addRow(new Object[]{"A1", "A2", 42});
model.addRow(new Object[]{"B1", "B2", 42d});
model.addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
// DML as indicated
}
});
table = new JTable(model);
this.add(table);
}
private void display() {
JFrame f = new JFrame("NewJavaGUI");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new NewJavaGUI().display();
}
});
}
}
The behaviour you mention can be achieved by forcing your table to start editing again.
First make sure you now yourRow and Column and that you add your own tablecelleditor that extands from the AbstractCellEditor
then add this to your stopCellEditing method:
EventQueue.invokeLater(new Runnable()
{
public void run()
{
yourTable.editCellAt( yourRow, yourColumn+1);
}
});
This is my first time asking here so forgive me if something isn't appropriate, and sorry if my English isn't very good.
Well, to make it short, currently I'm developing a Java desktop app with Swing and I have a problem using table. I have rows with each row have a button to delete the row. Everything is okay (i can delete rows with no problem) until i try to delete the last row. The last row can be deleted but apparently there is an exception, something like this:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 4 >= 4
at java.util.Vector.elementAt(Vector.java:427)
at javax.swing.table.DefaultTableModel.setValueAt(DefaultTableModel.java:648)
at javax.swing.JTable.setValueAt(JTable.java:2710)
at javax.swing.JTable.editingStopped(JTable.java:4712)
at javax.swing.AbstractCellEditor.fireEditingStopped(AbstractCellEditor.java:125)
From the stack trace, it seems that "4" is my previously deleted last row index, but i have no idea how to deal with this. I already search for solution but i still can't solve it. Note that there are still other rows when i delete the last row, and after that i can't delete the others rows. The same exception also resulted when i click the delete button.
Oh. and I use removeRow() from DefaultTableModel to delete the row. Any help will be appreciated. Thanks.
EDIT
These are the code I use.
public class ViewDetail extends JInternalFrame implements ActionListener {
...
String column[] = { "Aaa", "Bbb", "Delete This"};
tableModel = new DefaultTableModel();
Object row[][] = new Object[size][column.length];
//fill the data from db
int r = 0;
for (int i = 0; i < size; i++) {
row[r][0] = ...;
row[r][1] = ...;
row[r][2] = "Delete";
r++;
}
tableModel.setDataVector(row, column);
table = new JTable(tableModel);
tableColumn = table.getColumn("Aaa");
tableColumn.setPreferredWidth(75);
tableColumn = table.getColumn("Bbb");
tableColumn.setPreferredWidth(75);
tableColumn = table.getColumn("Delete This");
tableColumn.setPreferredWidth(75);
tableColumn.setCellRenderer(new ButtonRenderer());
tableColumn.setCellEditor(new ButtonEditor(new JCheckBox());
...
}
public class ButtonRenderer extends JButton implements TableCellRenderer {
public ButtonRenderer() {
setOpaque(true);
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (isSelected) {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(UIManager.getColor("Button.background"));
}
setText((value == null) ? "" : value.toString());
return this;
}
}
public class ButtonEditor extends DefaultCellEditor {
protected JButton button;
private String label;
private boolean isPushed;
private JTable table;
public ButtonEditor(JCheckBox checkBox) {
super(checkBox);
button = new JButton();
button.setOpaque(true);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireEditingStopped();
}
});
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
if (isSelected) {
button.setForeground(table.getSelectionForeground());
button.setBackground(table.getSelectionBackground());
} else {
button.setForeground(table.getForeground());
button.setBackground(table.getBackground());
}
label = (value == null) ? "" : value.toString();
button.setText(label);
isPushed = true;
this.table = table;
return button;
}
public Object getCellEditorValue() {
if (isPushed) {
DefaultTableModel tableModel = (DefaultTableModel) table.getModel();
tableModel.removeRow(table.getSelectedRow());
}
isPushed = false;
return new String(label);
}
public boolean stopCellEditing() {
isPushed = false;
return super.stopCellEditing();
}
protected void fireEditingStopped() {
super.fireEditingStopped();
}
}
Swing is trying to set the new value into the row you remove! Try moving the remove code into a Runnable and use invokeLater in the swing utility class to execute it.
could you post the code where you init, add elements and delete in your JTable?
My first guess is that you are either doing the classical mistake
"I have 4 elements in my table so to delete the last one I remove(4)" when you your table goes from 0 to 3 in indices
or you are trying to remove several object in the same loop like
for(int i = 0; i<lenght; i++){
if(i%2==0){//every even number
tab.remove(i);
}
}
then your are modifying the size of your table, the elements are shifted but your not taking it in account when removing.
those are just guesses/pointer to what might cause the problem. please post your code if this doesn't solve it
The Table Button Column shows how you can render a column as a button and how to add an Action that is executed when the button is clicked. The example Action just happens to show how to delete a row.
Here you need to remove only 0 th row that should be iterated
private void refreshTable() {
int rowCount= model.getRowCount();
// System.out.println(rowCount);
for(int i=0;i<rowCount;i++ ){
model.removeRow(0);
//System.out.println(i);
}
}
you can add new vaiable and check to fireEditingStopped() :
public class ButtonEditor extends DefaultCellEditor {
//create new variable
private boolean isDeleteRow = false;
/////////////////
protected JButton button;
private String label;
private boolean isPushed;
private JTable table;
public ButtonEditor(JCheckBox checkBox) {
super(checkBox);
button = new JButton();
button.setOpaque(true);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireEditingStopped();
}
});
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
if (isSelected) {
button.setForeground(table.getSelectionForeground());
button.setBackground(table.getSelectionBackground());
} else {
button.setForeground(table.getForeground());
button.setBackground(table.getBackground());
}
label = (value == null) ? "" : value.toString();
button.setText(label);
isPushed = true;
this.table = table;
// set false when click to button
isDeleteRow = false;
/////////////////
return button;
}
public Object getCellEditorValue() {
if (isPushed) {
// set true when isPushed button
isDeleteRow = true;
/////////////////
}
isPushed = false;
return new String(label);
}
public boolean stopCellEditing() {
isPushed = false;
return super.stopCellEditing();
}
protected void fireEditingStopped() {
super.fireEditingStopped();
//check if isDeleteRow, remove row
if(isDeleteRow)
{
DefaultTableModel tableModel = (DefaultTableModel) table.getModel();
tableModel.removeRow(table.getSelectedRow());
}
/////////////////
}
}