可编辑的 JComboBox 在失去焦点时触发 ActionListener

Editable JComboBox firing ActionListener when losing focus

我正在编写扩展 JComboBox 的 class (UIPromptComboBox)。组合框是可编辑的,对于 class 的一个应用程序,它是通过控制 ActionListener 实现的。

目前,编辑组合框时会触发 ActionListener,这很好。然而,当我取消选择组合框时,这个 ActionListener 也会被触发,我无法区分这两个事件,我也不希望它在取消选择组合框时触发。

实施Class

private void addUIField() {
        // Initialise and place combobox
        this.myGuiTextField = new UIPromptComboBox();
        myGuiTextField.setSize(COMBO_WIDTH, defaultHeight);
        GuiUtils.positionControl(myPanel, myGuiTextField, myTop, PROMPT_X_LOC);

        //Add action listener
        myGuiTextField.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent evt) {
                if (evt.getActionCommand().equals("comboBoxEdited")) {
                    newUIcreated((UIPromptComboBox) evt.getSource());
                }
            }

            private void newUIcreated(UIPromptComboBox alteredGuiTextField) {
                try {
                    UIPrompt uip = alteredGuiTextField.getUIPrompt(((PowerPointTextItem) myPPTRef).getValue());
                    if (!simInfo.isInPrompts(uip)) {
                        simInfo.addUIPrompt(uip);
                        alteredGuiTextField.addNewUIPrompt(uip);
                    }
                } catch (MissingPowerpointItem ex) {
                    Exceptions.printStackTrace(ex);
                }
            }
        });
    }

Class 扩展 JComboBox

public class UIPromptComboBox extends JComboBox {

    public UIPromptComboBox(UIPrompt[] items) {
        super(items);
        this.setEditable(true);
    }

    public UIPromptComboBox() {
        this.setEditable(true);
        this.setEnabled(false);
    }

    /**
     * returns either the selected UI prompt or a new prompt using the example
     * text
     *
     * @param exampleText only used if new prompt is created
     * @return UI prompt selected
     */
    public UIPrompt getUIPrompt(String exampleText) {
        UIPrompt uIPrompt = null;
        Object returnedItem = this.getSelectedItem();
        if (returnedItem instanceof UIPrompt) {
            uIPrompt = (UIPrompt) returnedItem;
        } else if (returnedItem instanceof String) {
            uIPrompt = new UIPrompt((String) returnedItem, exampleText);
        }
        return uIPrompt;
    }

    public void addNewUIPrompt(UIPrompt newPrompt) {
        ActionListener[] actionListerners = this.getActionListeners();

        this.removeActionListener(this);
        this.addItem(newPrompt);
        this.setSelectedItem(newPrompt);

        for (ActionListener al : actionListerners) {
            this.addActionListener(al);
        }

    }

    /**
     * Used for displaying a report value sentence
     * i.e. a string that is not associated with UI Prompts
     * @param newText report value sentence
     */
    public void setText(String newText) {
        this.removeAllItems();
        this.addItem(newText);
        this.setSelectedItem(newText);
    }

    /**
     * For when the UI prompts can be added on construction
     *
     * @param currentUIs list of UI promts
     */
    public void addItems(UIPrompt[] currentUIs) {
        this.removeAllItems();
        DefaultComboBoxModel boxModel = new DefaultComboBoxModel(currentUIs);
        this.setModel(boxModel);
    }

}

由于失去焦点导致多次触发导致创建多个对象并将其添加到列表中。我想我可能错误地实施了 ActionListener。感谢您的帮助

如您所述,您只希望在用户按下回车键时触发事件。实现它的更好方法是使用键监听器而不是动作监听器。

myGuiTextField.addKeyListener(new KeyAdapter() {
    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_ENTER) {
            newUIcreated((UIPromptComboBox) evt.getSource());
        }
    }

    private void newUIcreated(UIPromptComboBox alteredGuiTextField) {
           try {
                UIPrompt uip = alteredGuiTextField.getUIPrompt(((PowerPointTextItem) myPPTRef).getValue());
            if (!simInfo.isInPrompts(uip)) {
                simInfo.addUIPrompt(uip);
                alteredGuiTextField.addNewUIPrompt(uip);
            }
        } catch (MissingPowerpointItem ex) {
            Exceptions.printStackTrace(ex);
        }
    }
});

这应该只会在用户按下 enter 时触发您的事件 newUIcreated,而不会在其他时间触发。用这个替换你的动作监听器

终于找到问题了

UIPrompt 的显示包括添加一个有时包含换行符的字符串。

单击另一个字段的操作会触发 UIPrompt 的呈现,但是当它包含换行符时,它会再次触发 ActionListener。这就是 comboBoxEdited 重复操作的原因。