Why is cancelCellEditing() not called when pressing escape while editing a JTable cell?
Asked Answered
L

3

7

I have an editable JTable and have set a DefaultCellEditor like so:

    colModel.getColumn( 1 ).setCellEditor( new DefaultCellEditor( txtEditBox ) {
        // ...
        @Override
        public void cancelCellEditing() {
            super.cancelCellEditing();
            // handling the event
        }
        // ...
    }

However, when pressing escape while editing a cell in this column, though the editing mode is finished, this method is not called. Any ideas why? Am I doing something wrong? Is there a way to handle this (other than manually adding a KeyListener that is)?

Liquorish answered 20/12, 2010 at 14:45 Comment(0)
C
11

The official way: You can register a CellEditorListener: AbstractCellEditor.addCellEditorListener(...). If the editing is canceled, editingCanceled(ChangeEvent e) should be called. Due to a SUN bug https://bugs.java.com/bugdatabase/view_bug?bug_id=6788481, editingCanceled is not called :(

As workaround you can register your own action for the ESCAPE key and handle it yourself. But it will not work for resize events.

Another solution (quick and dirty;-)): Overwrite the methode JTable.removeEditor() and insert your code after the super call.

Chard answered 20/12, 2010 at 15:43 Comment(0)
R
0

I had this problem too. I wrote another workaround that involves ActionListener and FocusListener. This is it:

public class TableEditorListenerHelper {

// dealing with events
private final EventListenerList listeners = new EventListenerList();
private ChangeEvent changeEvent;

// cell editor that we're helping
private CellEditor editor;

// transient state
private boolean editing = false;
private JTable table;

public TableEditorListenerHelper(CellEditor editor, JTextField field) {
    this.editor = editor;
    field.addActionListener(new ActionListener() {
        @Override public void actionPerformed(ActionEvent e) {
            fireEditingStopped();
        }
    });
    field.addFocusListener(new FocusListener() {

        @Override public void focusGained(FocusEvent e) {
            editing = true;
        }

        @Override public void focusLost(FocusEvent e) {
            JTable table = TableEditorListenerHelper.this.table;
            if (editing && isEditing(table)) {
                fireEditingCanceled();
            }
        }

        private boolean isEditing(JTable table) { // a hack necessary to deal with focuslist vs table repaint
            return table != null && table.isEditing();
        }

    });
}

public void setTable(JTable table) {
    this.table = table;
}

public void addCellEditorListener(CellEditorListener l) {
    listeners.add(CellEditorListener.class, l);
}

public void removeCellEditorListener(CellEditorListener l) {
    listeners.remove(CellEditorListener.class, l);
}

public CellEditorListener[] getCellEditorListeners() {
    return listeners.getListeners(CellEditorListener.class);
}

protected void fireEditingCanceled() {
    for (CellEditorListener l : getCellEditorListeners()) {
        l.editingCanceled(getOrCreateEvent());
    }
    resetEditingState();
}

protected void fireEditingStopped() {
    for (CellEditorListener l : getCellEditorListeners()) {
        l.editingStopped(getOrCreateEvent());
    }
    resetEditingState();
}

private void resetEditingState() {
    table = null;
    editing = false;
}

private ChangeEvent getOrCreateEvent() {
    return changeEvent = changeEvent == null ? new ChangeEvent(editor) : changeEvent;
}

Here you can find a little more complete solution.

Ruelle answered 15/10, 2014 at 22:32 Comment(0)
G
0

Another way fix this bug:

jTable.addPropertyChangeListener("tableCellEditor", e -> {
    Object o = e.getOldValue();
    if (o instanceof DefaultCellEditor) {
        ((DefaultCellEditor) o).cancelCellEditing();
    }
});
Gocart answered 25/8, 2017 at 15:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.