Java AbstractAction иногда не обнаруживает escape-ключ - странное поведение - PullRequest
3 голосов
/ 19 июня 2010

В главном / подробном представлении у меня есть ряд текстовых полей (и один или два других элемента управления), которые все относятся к детализации выбранного в данный момент элемента. Все они имеют один и тот же 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, которую я пропускаю из-за недостатка сна, но на данный момент я совершенно ошарашен.

Ответы [ 2 ]

1 голос
/ 19 июня 2010

Проблема, с которой вы столкнулись, связана с настройкой текста подсказки.Как только вы это сделаете, ToolTipManager заменяет вашу клавишу действия отмены в inputMap своим собственным hideTip нажатием клавиши, также VK_ESCAE.

0 голосов
/ 19 июня 2010

Я предлагаю не прикреплять действия к каждому текстовому полю.Присоедините их к родительскому контейнеру, а при извлечении из него входной карты используйте условие WHEN_ANCESTOR_OF_FOCUSED_COMPONENT.

Таким образом, когда этот контейнер находится в фокусе, будут доступны действия

...