简体   繁体   English

Java AbstractAction有时不会检测转义键 - 奇怪的行为

[英]Java AbstractAction sometimes not detecting escape key - bizarre behaviour

In a master/detail 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. 它们都共享相同的DocumentListener因此如果您更改其中任何一个,则会启用一对“保存”/“丢弃”按钮。 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). 但是,当我使用InputMapActionMap将共享saveAction附加到enter键并将共享discardAction附加到转义键时,discardAction仅适用于某些字段(saveAction适用于所有字段)。

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. 记录时我可以看到,对于有效的字段,首先触发discardAction,然后是removeUpdate和insertUpdate的适当组合。

For the fields that don't work the discardAction is never triggered. 对于不起作用的字段,不会触发discardAction。 Enough chitter, chatter - here is the pertinent code (copy and paste, not paraphrase): 足够的chitter,chatter - 这是相关的代码(复制和粘贴,而不是释义):

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() ). 所有文本字段都以相同的方式registerDetailField()使用registerDetailField() )。 They also have putClientProperty called on them to allocate them a type for validation (see below). 他们还调用了putClientProperty为它们分配一个类型进行验证(见下文)。

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. discardAction SEEMS首先触发有效字段,但不起作用的字段都有共同的自定义验证。

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. 希望这是我的verifyField方法的一个简单问题,我因为睡眠不足而忽略了,但此刻我完全被难倒了。

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. 一旦你这样做, ToolTipManager就会用你自己的hideTip键击,也就是VK_ESCAE替换inputMap中的discard action键。

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. 将它们附加到父容器,并在从中检索输入映射时 - 使用WHEN_ANCESTOR_OF_FOCUSED_COMPONENT条件。

This way whenever this container is in focus actions will be available 这样,只要此容器处于焦点,就可以使用操作

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM