Java Tips Weblog

  • Blog Stats

    • 1,300,369 hits
  • Categories

  • Archives

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.

About these ads

36 Responses to “Table Stop Editing”

  1. 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 :)

  2. 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!

  3. 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.

  4. 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.

  5. 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.

      • 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. ;)

  6. This code worked great for me! Many thanks!

    if (table.isEditing())
    table.getCellEditor().stopCellEditing();

  7. joan fabi said

    this is a very helpful tip, thanks so much!

  8. Thanks a lot for the solution! Managed to get to this page through nested links..:) Thanks a lot..

  9. Anonymous said

    thank you for providing a helpful information… its solve my problem.. heheh

  10. Anonymous said

    I just want to say thank you very much.

  11. 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!

  12. 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.

  13. Manish said

    Thanks a lot…You saved my day !!

  14. jVel said

    Fantastic! Thanks a lot!

  15. Awad Jeries said

    Thank you very much!!!!!!!

  16. Atul Vairale said

    Marvellous…Thanks….You saved my lot of time..

  17. Simone said

    Great!
    Just what I was looking for , thanks :-)

  18. Thakur G said

    Hey Thanks…
    You are too good.

  19. Adam said

    I’ve spend a day already making this work and with your suggestions it just worked… straightaway!

    Thanks!

  20. Anonymous said

    thnk u very much…………very useful………

  21. Anonymous said

    Thank you! This doku is missing in the javadoc!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

Join 97 other followers

%d bloggers like this: