java - 单击边框时 JComboBox 弹出窗口立即出现和隐藏(糟糕的用户体验)

标签 java swing jcombobox user-experience visual-glitch

当您有一个 swing JComboBox 并单击其边框时,弹出窗口会立即出现并消失。当我说单击时,我的意思是按下鼠标左键并立即松开。

enter image description here

这可能被认为是糟糕的用户体验,因为没有用户会期望它发生。单击组合框的边框时,任何用户都会期望以下行为之一:

  1. 要打开并保持打开状态的弹出窗口,
  2. 或者根本不打开。

肯定没有用户会期望弹出窗口立即打开和关闭。

用户不是故意点击边框的。但是当组合框很小并且他试图快速点击它时,它可能会经常发生。

在 2000 年,有人将此行为注册为 openjdk 站点中的错误:https://bugs.openjdk.java.net/browse/JDK-4346918

他们已将其识别为一个错误,但通过以下解决方案将其关闭:“不会修复”,观察如下:

I've been able to reproduce the problem but it's not significant so I'm not going to fix it. The problem is that the drop down portion of the combo box will hide when the mouse is released after clicking on the border. This bug doesn't have a very major impact.

我同意他们的观点,它并没有产生非常大的影响。但我仍然认为这会导致糟糕的用户体验,我想知道是否有一种简单的解决方法可以使弹出窗口在用户单击其边框时保持打开状态或根本不打开。

可以通过在任何 JComboBox 的边框上单击鼠标左键来重现所描述的行为。请参阅下面可以复制的简单代码:

import java.awt.FlowLayout;
import javax.swing.*;

public class JComboBoxUX{
    public static void main(String[] args){
        SwingUtilities.invokeLater(new Runnable(){
            @Override
            public void run(){
                JComboBox<String> combobox = new JComboBox<String>(
                        new String[]{"aaaaaaaaaa","bbbbbbbb","ccccccccc"});

                JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10));
                panel.add(combobox);

                JFrame frame = new JFrame("JComboBox UX");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setContentPane(panel);
                frame.setSize(300, 150);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}

最佳答案

问题似乎出在:

class BasicComboPopup extends ... {

    private Handler getHandler() {
        if (handler == null) {
            handler = new Handler();
        }
        return handler;
    }

    private class Handler implements ... MouseListener ... {

        public void mouseReleased(MouseEvent e) {
            //...
            Component source = (Component)e.getSource();
            Dimension size = source.getSize();
            Rectangle bounds = new Rectangle( 0, 0, size.width - 1, size.height - 1 );
            if ( !bounds.contains( e.getPoint() ) ) {
                //...
                comboBox.setPopupVisible(false);
            }
        }
    }
}

通过从 size.widthsize.height 中减一,鼠标落在箭头按钮的边界之外,弹出菜单被隐藏。

解决这个问题是有问题的。 Handler 类是private,所以我们不能扩展它,getHandler()private,所以我们也不能在 BasicComboPopup 中覆盖它。

可以扩展 MetalComboBoxUI 并覆盖 createPopup() 以返回自定义 ComboPopup,例如扩展 BasicComboPopup > 但扩展 createMouseListener() 以返回与上面的 Handler 类似的类,但没有减法。

哦,对您希望支持的每个 LAF 执行相同的操作。嗯。

从另一个方向解决问题,可以扩展 MetalComboBoxButton(由 e.getSource() 返回)并覆盖 getSize() 方法在显示菜单时返回在两个方向上大一个像素的尺寸。当然,您仍然需要扩展和覆盖 MetalComboBoxUI 来创建和安装这个自定义按钮。

同样,您需要为您希望支持的每个 LAF 执行相同的操作。再次,yuk。

不幸的是,Swing 似乎没有所需的钩子(Hook)来轻松覆盖所需的功能,并且已将各种类标记为私有(private)内部实现细节,以防止它们被重用(以防止以后如果他们想要更改内部结构而损坏).

关于java - 单击边框时 JComboBox 弹出窗口立即出现和隐藏(糟糕的用户体验),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41062918/

相关文章:

java - 使用 JAR 文件对性能造成影响

java - 使用 lombok 注释的继承会出错

java - 找不到正确的匹配时,java程序崩溃

java - BoxLayout 无法将奇数宽度的单个元素居中对齐

java - 删除 JTable 单元格中可编辑 JCombobox 的边框

java - 如果我在项目可见时添加项目,则不会调整 JComboBox 弹出窗口的大小

java字符转换为二维字符数组中的数字

java - 编译前更改版本常量

java - 打开电子邮件客户端,并将 JFreeChart 的图表(图像)粘贴到正文中

Java Swing动态JComboBox