Java AbstractAction sometimes not detecting escape key - bizarre behaviour
In a master/d开发者_如何学Pythonetail view I have a series of text fields (and one or two other controls) that all pertain to the detail of the currently selected item. They all share the same DocumentListener
so if you change any of them a pair of "save"/"discard" buttons become enabled. The buttons invoke a method and I can happily save/discard items.
However, when I use InputMap
and ActionMap
to attach a shared saveAction to the enter key and a shared discardAction to the escape key the discardAction only works on some fields (saveAction works for them all).
When logging I can see that for the fields that work the discardAction is triggered first, followed by the appropriate combination of removeUpdate and insertUpdate.
For the fields that don't work the discardAction is never triggered. Enough chitter, chatter - here is the pertinent code (copy and paste, not paraphrase):
docChangeListener = new DocumentListener() {
public void insertUpdate(DocumentEvent de) {
System.out.println("\t insertUpdate just got triggered");
memberDetailsChanged(de);
}
public void removeUpdate(DocumentEvent de) {
System.out.println("\t removeUpdate just got triggered");
memberDetailsChanged(de);
}
public void changedUpdate(DocumentEvent de) {
// Not a styled document, safely ignore
}
};
saveAction = new AbstractAction() {
public void actionPerformed(ActionEvent ae) {
System.out.println("\t saveAction just got triggered");
saveChanges();
}
};
discardAction = new AbstractAction() {
public void actionPerformed(ActionEvent ae) {
System.out.println("\t discardAction just got triggered");
discardChanges();
}
};
private void registerDetailField(final JTextField field) {
field.getDocument().putProperty("field", field);
field.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), "saveActionKey");
field.getActionMap().put("saveActionKey", saveAction);
field.getInputMap().put(KeyStroke.getKeyStroke("ESCAPE"), "discardActionKey");
field.getActionMap().put("discardActionKey", discardAction);
field.getDocument().addDocumentListener(docChangeListener);
}
All the text fields are registered the same way (using registerDetailField()
). They also have putClientProperty
called on them to allocate them a type for validation (see below).
The ONLY difference between the fields that work and the fields that don't is the actual validation process. I'll cut it down because it is so long but I feel I have to include it. discardAction SEEMS to fire first for the fields that work but the fields that don't work all have custom validation in common.
private void verifyField(final JTextField field) {
int fieldType = ((Integer)field.getClientProperty("type")).intValue();
String fieldValue = field.getText();
switch (fieldType) {
case STANDARD_FIELD:
return; // No validation at the moment
case MEMBER_NUMBER_FIELD:
if (fieldValue.length() == 0) { // Field is required
field.setBackground(REQUIRED_COLOUR);
field.setToolTipText("This is a required field");
invalidFields.add(field);
return;
}
// Check proposed value is valid
if (customTableModel.memberNumStringIsValid(fieldValue,
selectedMember.getMemberNumber())) {
field.setBackground(NORMAL_COLOUR);
field.setToolTipText(null);
invalidFields.remove(field);
} else {
field.setBackground(ERROR_COLOUR);
field.setToolTipText("This value must be a unique,
positive number");
invalidFields.add(field);
}
return;
/* SNIP */
default:
return;
}
}
Hopefully it's a simple problem with my verifyField method that I'm overlooking due to lack of sleep but at the moment I'm completely stumped.
The problem you are having is with the setting of the tool tip text. Once you do that, the ToolTipManager
is replacing your discard action key in the inputMap with its own hideTip
key stroke, also VK_ESCAE.
I wold suggest to NOT attach actions to each text field. Attach them to the parent container and when retrieving input map from it - use WHEN_ANCESTOR_OF_FOCUSED_COMPONENT condition.
This way whenever this container is in focus actions will be available
精彩评论