提问者:小点点

Java8中的可编辑JComboBox不会将Enter键转发到默认按钮


我有一个可编辑的JComboBox,重点放在这个组合框上,当我按Enter键时,与旧版本相比,Java8的行为有所不同。

此代码在Java7及以下版本中按预期工作,但在Java8(在Oracle中测试JVM在Mac中测试)中则不然:

package org.wiztools.comboboxdefaultbutton;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;

/**
 *
 * @author subhash
 */
public class MyFrame extends JFrame {

    private static MyFrame me;

    public MyFrame() {
        Container c = getContentPane();
        c.setLayout(new BorderLayout());

        // Press Enter key with focus on this component:
        JComboBox jcb = new JComboBox(new String[]{"Option: One", "Option: Two"});
        jcb.setEditable(true);
        c.add(jcb, BorderLayout.CENTER);

        JButton jb = new JButton("Ok");
        jb.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(me, "Button pressed!");
            }
        });
        SwingUtilities.getRootPane(c).setDefaultButton(jb);
        c.add(jb, BorderLayout.EAST);

        pack();
        setVisible(true);
    }

    public static void main(String[] arg) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                me = new MyFrame();
            }
        });
    }
}

如何让这段代码在Java8及以下统一工作?


共2个答案

匿名用户

我在JDK7的BasicComboBoxUIHandler类中找到了以下代码。Handler作为ActionListener添加到编辑器中:

//
// ActionListener
//
// Fix for 4515752: Forward the Enter pressed on the
// editable combo box to the default button

// Note: This could depend on event ordering. The first ActionEvent
// from the editor may be handled by the JComboBox in which case, the
// enterPressed action will always be invoked.
public void actionPerformed(ActionEvent evt) {
    Object item = comboBox.getEditor().getItem();
    if (item != null) {
     if(!comboBox.isPopupVisible() && !item.equals(comboBox.getSelectedItem())) {
      comboBox.setSelectedItem(comboBox.getEditor().getItem());
     }
     ActionMap am = comboBox.getActionMap();
     if (am != null) {
        Action action = am.get("enterPressed");
        if (action != null) {
            action.actionPerformed(new ActionEvent(comboBox, evt.getID(),
                                   evt.getActionCommand(),
                                   evt.getModifiers()));
        }
    }
}

我想你可以检查JDK8源代码以查看是否进行了任何更改。

如果已经进行了更改,那么您可能需要创建自己的ActionListener,调用组合框的“尽管如此”操作,并手动将此操作添加到组合框的编辑器中。

匿名用户

这个4岁bug的一个简短解决方法:

comboBox.getEditor().getEditorComponent().addKeyListener(new KeyAdapter() {
    @Override
    public void keyPressed(KeyEvent e) {
        if (!comboBox.isPopupVisible() && e != null && e.getKeyCode() == KeyEvent.VK_ENTER) {
            Container parent = comboBox.getParent();
            if (parent != null) parent.dispatchEvent(e);
        }
    }
});

由于某种原因,BasicComboBoxUI跳过了容器层次结构,并将enter键事件直接传递给JRootPane以“调用默认按钮绑定”(无论是什么,它都不是JOptionPane对话框中的默认按钮)。此侦听器手动将键事件传递给父容器。