使用键盘滚动弹出列表时如何使 JComboBox 选定的项目不更改

发布于 2024-10-20 07:44:32 字数 229 浏览 4 评论 0原文

我在面板中有一个 JComboBox 组件,并附加了 ItemListener。但每次按下向上/向下按键后(滚动打开的弹出列表时)它都会被触发。我想在用户通过按 Enter 键接受选择后更改所选值。

使用鼠标时则不会出现这种情况。当我将鼠标移到组合框的列表上时,突出显示会跟随鼠标指针,但在按下鼠标按钮之前,所选项目不会更改。我希望键盘具有相同的行为,即通过向上/向下箭头移动突出显示不会更改所选项目,但按 Enter 会更改。

I have a JComboBox component in the panel and ItemListener attached to it. But it gets fired after every up/down keypress (when scrolling though opened popup list). I want to change the selected value after the user accepts selection by pressing for example Enter key.

This is not a case when using mouse. When I move mouse over the combobox's list the highlight follows mouse pointer, but selected item is not changed until I press the mouse button. I would like to have the same behavior for keyboard, i.e. moving highlight via up/down arrow does not change selected item, but pressing Enter does.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

┈┾☆殇 2024-10-27 07:44:32

我相信您应该能够执行以下操作:

comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);

在将 comboBox 实例创建到 获取此功能

I believe you should be able to do:

comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);

after you have created your comboBox instance to get this functionality

指尖凝香 2024-10-27 07:44:32

在 Java 8 中,他们修复了这一行为,但只有在您设置一个 UI 属性时才会触发

UIManager.getLookAndFeelDefaults().put("ComboBox.noActionOnKeyNavigation", true);

In Java 8 they have fixed this behaviour, but only trigger if u set one UI property

UIManager.getLookAndFeelDefaults().put("ComboBox.noActionOnKeyNavigation", true);
笑叹一世浮沉 2024-10-27 07:44:32

JComboBox.isTableCellEditor 方法适用于列表中的箭头移动,但不适用于 KeySelectionManager 支持的预输入。即,您仍然会为用户键入的每个非导航键获取 ActionEvents,因为 JComboBox 解释这些字符以通过模型进行搜索以移动到(或靠近)用户的预期选择。

这个解决方案有一个缺点,它改变了鼠标点击的操作命令,这对我来说是一个不错的妥协,因为 GUI 的流程迫使用户将焦点从组合框上移开,

我最终制作了一个特殊的 KeyListener,它依赖于将组合框的默认操作命令从 comboBoxChanged 更改为 comboBoxMovement。这是组合框全部初始化后我需要的代码行:

setExplicitSelectionManager(myComboBox);

...这是完成所有工作的方法及其包含的类:

private void setExplicitSelectionManager(JComboBox comboBox) {

    class ExplicitSelectionManager implements KeyListener, FocusListener {

        private JComboBox src;
        private KeyListener superKeyListener;

        ExplicitSelectionManager(JComboBox src) {
            this.src = src;

            //   we like what the default key listener does, but not the action command
            // it uses for ActionEvents it fires for plain text type-ahead characters
            this.superKeyListener = src.getKeyListeners()[0]; // we only have one
            src.removeKeyListener(superKeyListener); // will be replace right away, below
        }

        @Override
        public void keyTyped(KeyEvent e) {
            // basic combo box has no code in keyTyped
        }

        @Override
        public void keyPressed(KeyEvent e) {

            //   in the default JComboBox implementation, the KeySelectionManager is
            // called from keyPressed. I'm fine with the implementation of
            // the default, but I don't want it firing ActionEvents that will cause
            // model updates
            src.setActionCommand("comboBoxMovement");
            this.superKeyListener.keyPressed(e);
            src.setActionCommand("comboBoxChanged");

            if (e.getKeyCode() == 10) {
                src.setSelectedIndex(src.getSelectedIndex());
            }
        }

        @Override
        public void keyReleased(KeyEvent e) {
            // basic combo box has no code in keyReleased
        }

        @Override
        public void focusGained(FocusEvent e) {
        }

        @Override
        //  this will also give us the event we want, if the user decides to Tab out of
        // the combo box, instead of hitting Enter
        public void focusLost(FocusEvent e) {
            src.setSelectedIndex(src.getSelectedIndex());
        }
    }

    ExplicitSelectionManager newSelectionManager = new ExplicitSelectionManager(comboBox);

    comboBox.addKeyListener(newSelectionManager);
    comboBox.addFocusListener(newSelectionManager);

}

...这是执行操作的方法

private void comboBoxActionPerformed(java.awt.event.ActionEvent evt) {                                                

    JComboBox source = (JComboBox) evt.getSource();

    //     "comboBoxChanged" is the default, 
    // so any normal JComboBox can also use this action listener
    if (evt.getActionCommand().equals("comboBoxChanged")) {
        updateModel(source.getName(), (String) source.getSelectedItem());
    }
}                                               

the JComboBox.isTableCellEditor method works for arrow movement through the list, but does not work for type-ahead supported by the KeySelectionManager. i.e. you still get ActionEvents for every non-navigation key the user types, as the JComboBox interprets those characters for searching though the model to move to (or move close to) the user's intended selection.

this solution has a drawback in that it changes the action command for mouse clicks, which was a OK compromise for me because the the flow of the GUI forces the user to change the focus away from the combo box

I ended up making a special KeyListener, that relys on changing the combo box's default action command from comboBoxChanged to comboBoxMovement. Here's the line of code I need after my combo box is all initialized:

setExplicitSelectionManager(myComboBox);

... and here is the method and its contained class that do all the work:

private void setExplicitSelectionManager(JComboBox comboBox) {

    class ExplicitSelectionManager implements KeyListener, FocusListener {

        private JComboBox src;
        private KeyListener superKeyListener;

        ExplicitSelectionManager(JComboBox src) {
            this.src = src;

            //   we like what the default key listener does, but not the action command
            // it uses for ActionEvents it fires for plain text type-ahead characters
            this.superKeyListener = src.getKeyListeners()[0]; // we only have one
            src.removeKeyListener(superKeyListener); // will be replace right away, below
        }

        @Override
        public void keyTyped(KeyEvent e) {
            // basic combo box has no code in keyTyped
        }

        @Override
        public void keyPressed(KeyEvent e) {

            //   in the default JComboBox implementation, the KeySelectionManager is
            // called from keyPressed. I'm fine with the implementation of
            // the default, but I don't want it firing ActionEvents that will cause
            // model updates
            src.setActionCommand("comboBoxMovement");
            this.superKeyListener.keyPressed(e);
            src.setActionCommand("comboBoxChanged");

            if (e.getKeyCode() == 10) {
                src.setSelectedIndex(src.getSelectedIndex());
            }
        }

        @Override
        public void keyReleased(KeyEvent e) {
            // basic combo box has no code in keyReleased
        }

        @Override
        public void focusGained(FocusEvent e) {
        }

        @Override
        //  this will also give us the event we want, if the user decides to Tab out of
        // the combo box, instead of hitting Enter
        public void focusLost(FocusEvent e) {
            src.setSelectedIndex(src.getSelectedIndex());
        }
    }

    ExplicitSelectionManager newSelectionManager = new ExplicitSelectionManager(comboBox);

    comboBox.addKeyListener(newSelectionManager);
    comboBox.addFocusListener(newSelectionManager);

}

... and here's the action performed method

private void comboBoxActionPerformed(java.awt.event.ActionEvent evt) {                                                

    JComboBox source = (JComboBox) evt.getSource();

    //     "comboBoxChanged" is the default, 
    // so any normal JComboBox can also use this action listener
    if (evt.getActionCommand().equals("comboBoxChanged")) {
        updateModel(source.getName(), (String) source.getSelectedItem());
    }
}                                               
笑红尘 2024-10-27 07:44:32

这是 ItemListener 的预期行为。每当显示的值发生变化时,就会触发该事件。根据您的要求,请使用 ActionListener

Its the expected behavior with the ItemListener. whenever the displayed value changes the event is fired. For your requirement use an ActionListener.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文