Why is cancelCellEditing() not called when pressing escape while editing a JTable cell?
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
}
开发者_Go百科 // ...
}
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)?
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 http://bugs.sun.com/bugdatabase/view_bug.do?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.
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.
Another way fix this bug:
jTable.addPropertyChangeListener("tableCellEditor", e -> {
Object o = e.getOldValue();
if (o instanceof DefaultCellEditor) {
((DefaultCellEditor) o).cancelCellEditing();
}
});
精彩评论