Table Stop Editing
Posted by Rob Camick on December 12, 2008
When editing a cell in a JTable the table doesn’t know when a user is finished editing the cell. Therefore it is the users responsibility to tell the table when to stop editing. This is normally done by:
- using the enter key
- tabbing to the next cell
- clicking on another cell with the mouse
In all the above cases the table will stop the cell editing and save the value to the table model for you. However, there is one case that is not handled automatically by the table. That is, what should happen when a user clicks on a component other than the table?
Lets assume you have some buttons on your form that will take data from the table. In this case you would want the data to be saved automatically when the button is clicked. There are two options to solving this problem.
The first is to have the table automatically stop editing and save the data. This can be done by setting a property on the table:
JTable table = new JTable(...);
table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
Note that this solution will cause the table to stop editing when any component get focus. I believe this logic is limited to components on the current window, but must admit I haven’t tested it. This solution will also not work when you click on the window buttons (ie, minimize or close).
Maybe the above solution is too general, and you want to control which components should stop editing. In this second case, you would need to add some code to the ActionListener of your buttons, something like:
if (table.isEditing())
table.getCellEditor().stopCellEditing();
This approach is a little more work, but it does give you full control as to when editing should be stopped.
It should be noted that clicking on a JTableHeader does not cause the table to lose focus. Therefore you will need to add a MouseListener to the table header and use the second approach to stop editing.
Sudar said
Thanks Rob, for documenting this. You really saved my day.:)
I have a deadline to meet in another 30 minutes, but this small issue was really stopping me. I have been fire-fighting this issue for quite sometime without any success.
I applied your fix and bingo!! it started to work. :)
My heart felt thanks to you :)
Rob Camick said
Glad a fire was put out. Thanks for the feedback.
kyle said
OMG!! This problem was bothering me for hours and I never thought I’d find a solution!! I wish this tutorial came up directly from google but I was linked in from another page. Thanks!
Rob Camick said
Glad your searching paid off.
Dinesh Bajaj said
Hi Rob,
My heartfelt thanks to you for posting these useful tips. I develop applications using Swing, and I find your tips most relevant and helpful.
Please keep doing the great work.
Rob Camick said
Thanks for the positive feedback.
Yan Cheng CHEOK said
This seem to be a pretty useful information. As I can seldom find tip and trick for Swing programming. Now I found one! :)
I will add this to my Delicious.
Rob Camick said
Glad the tips are useful.
Dmitriy Pushkov said
This one is what I am really looking for!.. But the next problem appeared after adding this line:
table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
The problem is if I have, for example, Float type of the column being edited, enter an empty string in corresponding cell and then click on any other control of the window – Java throws NullPointerException in CellEditorRemover.propertyChange() method of JTable.java. It uses getCellEditor() call to stop or cancel editing but it returns null in this case. If the value entered is not empty or if I remove terminateEditOnFocusLost flag everything is fine.
Is it a bug?.. I don’t know what to do…
Rob Camick said
I can also reproduce the problem so I would say it is a bug. Sorry, I don’t know how to fix it. If I think of something I’ll post the suggestion here.
Dmitriy Pushkov said
Hello, Rob. Thanks for your reply.
I hope I can provide a solution. It’s not so trivial as I supposed before but seems to me it works.
I had to inherit my own cell editor from default cell editor and my own text field from JTextField which has FocusListener. This focus listener works fine when editing cell loses the focus, and the focus gained by another control of the window. But in the case of cell selection changes focus listener is “deaf”. That’s why I also have to remember previously valid value before editing start to restore it if the entered value will be invalid.
Please, see the code below. Tested with Double, Float and Integer, but I hope this will also work with Byte and String. If you have any suggestions to improve or change the code I will be happy to listen to them too. :)
Text field with focus listener:
public class TextFieldCell extends JTextField {
public TextFieldCell(JTable cellTable) {
super(); // calling parent constructor
final JTable table = cellTable; // this one is required to get cell editor and stop editing
this.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
}
// this function successfully provides cell editing stop
// on cell losts focus (but another cell doesn't gain focus)
public void focusLost(FocusEvent e) {
CellEditor cellEditor = table.getCellEditor();
if (cellEditor != null)
if (cellEditor.getCellEditorValue() != null)
cellEditor.stopCellEditing();
else
cellEditor.cancelCellEditing();
}
});
}
}
Default cell editor class:
class TextFieldCellEditor extends DefaultCellEditor {
TextFieldCell textField; // an instance of edit field
Class columnClass; // specifies cell type class
Object valueObject; // for storing correct value before editing
public TextFieldCellEditor(TextFieldCell tf, Class cc) {
super(tf);
textField = tf;
columnClass = cc;
valueObject = null;
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
TextFieldCell tf = (TextFieldCell)super.getTableCellEditorComponent(table, value, isSelected, row, column);
if (value != null) {
tf.setText(value.toString());
}
// we have to save current value to restore it on another cell selection
// if edited value couldn't be parsed to this cell's type
valueObject = value;
return tf;
}
@Override
public Object getCellEditorValue() {
try {
// converting edited value to specified cell's type
if (columnClass.equals(Double.class))
return Double.parseDouble(textField.getText());
else if (columnClass.equals(Float.class))
return Float.parseFloat(textField.getText());
else if (columnClass.equals(Integer.class))
return Integer.parseInt(textField.getText());
else if (columnClass.equals(Byte.class))
return Byte.parseByte(textField.getText());
else if (columnClass.equals(String.class))
return textField.getText();
}
catch (NumberFormatException ex) {
}
// this handles restoring cell's value on jumping to another cell
if (valueObject != null) {
if (valueObject instanceof Double)
return ((Double)valueObject).doubleValue();
else if (valueObject instanceof Float)
return ((Float)valueObject).floatValue();
else if (valueObject instanceof Integer)
return ((Integer)valueObject).intValue();
else if (valueObject instanceof Byte)
return ((Byte)valueObject).byteValue();
else if (valueObject instanceof String)
return (String)valueObject;
}
return null;
}
}
It the code of table initialization you have to add the following:
myTable.setDefaultEditor(Float.class, new TextFieldCellEditor(new TextFieldCell(myTable), Float.class));
myTable.setDefaultEditor(Double.class, new TextFieldCellEditor(new TextFieldCell(myTable), Double.class));
myTable.setDefaultEditor(Integer.class, new TextFieldCellEditor(new TextFieldCell(myTable), Integer.class));
Hope, this will help somebody who have the same problem. Thanks for your blog again, Rob. ;)
Kevin Isabelle said
This code worked great for me! Many thanks!
if (table.isEditing())
table.getCellEditor().stopCellEditing();
Rob Camick said
Glad it helped.
joan fabi said
this is a very helpful tip, thanks so much!
Rob Camick said
Thanks for the feedback.
Sudha Kannan said
Thanks a lot for the solution! Managed to get to this page through nested links..:) Thanks a lot..
Rob Camick said
Better late than never! Glad a link finally led you to this page.
Anonymous said
thank you for providing a helpful information… its solve my problem.. heheh
Anonymous said
I just want to say thank you very much.
Rob Camick said
Thanks for taking the time to comment.
Ranga said
I was also having this problem and I remembered this link from ranch. This is a cool tip!
I know its hard to find the solution the first time though…
Thanks for saving me a lot of time!
Rob Camick said
Glad you found the tip in the ranch.
Greevous said
This is one of the things I hate about java (more specifically AWT and Swing). The most logical behavior would be for the underlying model to update WITH EVERY KEYSTROKE, unless you specifically ask for some other editor behavior. I should not have to think about the fact that the editor text field is something different than the cell that eventually renders when the editor text field loses focus — that’s an implementation detail unique to the way AWT and Swing works, and I SHOULDN’T HAVE TO CARE ABOUT IT. The jokers who built AWT and Swing clearly went inside->out (from code to user interface) rather than outside->in (ideal UI behavior to code) when they designed the architecture of these silly components. They were in love with objects and class hierarchies, and could care less about end users.
As Dr. Steven Covey said: “Start with the end in mind.” In this case, if you’re charged with building up a library of GUI components, start with “HOW WILL PEOPLE NORMALLY USE THESE THINGS?” How many countless hours have been wasted by programmers trying desperately to get around some stupid flaky behavior of these controls that SHOULDN’T HAVE EVEN BEEN THERE IN THE FIRST PLACE!! And then, to top it all off, the geniuses at Oracle (formerly Sun) will argue with you when you submit a bug report about how a control should normally behave, as if it’s even debatable. They all need to be sent through HCI training over and over again until they can score 100% on some standardized GUI interaction design test.
Sorry for the rant… had to get that off my chest… I just wasted 3 hours of my life until I found this page. Thank you to the author.
Rob Camick said
No, the model should NOT be updated on every keystroke. The model should only ever contain valid data.
Manish said
Thanks a lot…You saved my day !!
Rob Camick said
Glad the suggestion helped.
jVel said
Fantastic! Thanks a lot!
Rob Camick said
Glad the tip helps.
Awad Jeries said
Thank you very much!!!!!!!
Atul Vairale said
Marvellous…Thanks….You saved my lot of time..
Simone said
Great!
Just what I was looking for , thanks :-)
Rob Camick said
Thanks, glad the search paid off.
Thakur G said
Hey Thanks…
You are too good.
Adam said
I’ve spend a day already making this work and with your suggestions it just worked… straightaway!
Thanks!
Anonymous said
thnk u very much…………very useful………
Anonymous said
Thank you! This doku is missing in the javadoc!
Anonymous said
Thank you :-)
Anonymous said
Thank you very much good sir! This still helped me and my company a ton in 2016 :-)
Anonymous said
Thank for this useful tip.
Cory said
It’s a pleasure to find such a nice piece of explanation.
It helped to fix my issue with plenty JComboBoxes within a JTableCell and a Header which is supposed to reorder the contents via Column-Values.
I put it on the mouseClicked-Event of my MouseAdapter after checking if any celleditor is active, before any other action happens. It works great.
Thank you very much!
Kind Regards
Cory
Rob Camick said
Glad the suggestion solved your problems.
Dimpy Chhabra said
Hi! This article was much helpful, but I am yet new at java. I am using netbeans and making a basic management project.
I tried to edit a jTable and push it into a mysql table, was getting the following exception :java.lang.ArrayIndexOutOfBoundsException: 5 >= 5
Hope that gets solved.
Now my ques :
In order to use the second one.. if isediting, stop cell editor”, what library do I need to import ??
It gives an error for just adding those two lines in my “private void jButton2ActionPerformed(java.awt.event.ActionEvent evt)”, error:.
Please reply as soom as possible.
Much appreciation.
samruddhi03 said
Reblogged this on Samruddhi and commented:
Stop JTable Editing !!!
samruddhi03 said
ThankYou sooo sooo much for this article ! I have been stuck at this issue for days !! Thanks A Lot Again !!!
Anonymous said
Thank You! Danke!
Anonymous said
Thank You So Much ! It helps me a lot !