В главном / подробном представлении у меня есть ряд текстовых полей (и один или два других элемента управления), которые все относятся к детализации выбранного в данный момент элемента. Все они имеют один и тот же DocumentListener
, поэтому при изменении любого из них становится доступной пара кнопок «сохранить» / «сбросить». Кнопки вызывают метод, и я могу с радостью сохранять / удалять элементы.
Однако, когда я использую InputMap
и ActionMap
для присоединения общего saveAction к ключу ввода и общего discardAction к escape-ключу, discardAction работает только для некоторых полей (saveAction работает для них всех).
При ведении журнала я вижу, что для полей, которые работают, сначала запускается discardAction, а затем соответствующая комбинация removeUpdate и insertUpdate.
Для полей, которые не работают, действие discardAction никогда не запускается. Достаточно болтовни, болтовни - вот соответствующий код (скопируйте и вставьте, а не перефразируйте):
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);
}
Все текстовые поля регистрируются одинаково (используя registerDetailField()
). У них также есть вызов putClientProperty
для присвоения им типа для проверки (см. Ниже).
ЕДИНСТВЕННАЯ разница между полями, которые работают, и полями, которые не работают, является фактическим процессом проверки. Я урежу это, потому что это так долго, но я чувствую, что должен включить это. discardAction СЛЕДУЕТ запускать в первую очередь для полей, которые работают, но все поля, которые не работают, имеют общую обычную проверку.
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;
}
}
Надеюсь, это простая проблема с моим методом verifyField, которую я пропускаю из-за недостатка сна, но на данный момент я совершенно ошарашен.