如何在使用自定义ListCellRenderer时防止JComboBox无响应 [英] How to prevent JComboBox from becoming unresponsive when using a custom ListCellRenderer

查看:226
本文介绍了如何在使用自定义ListCellRenderer时防止JComboBox无响应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 JComboBox 和自定义 ListCellRenderer 制作字体选择器。我想要
JComboBox 来显示所有可用字体,每个字体名称都以自己的字体显示。我目前使用大约500种字体。

I am making a font chooser using JComboBox and a custom ListCellRenderer. I want the JComboBox to display all available fonts, with each font name displayed in its own font. I am currently using around 500 fonts.

提供此功能的 ListCellRenerer 的示例:

private class ComboBoxRenderer extends JLabel implements ListCellRenderer {

    private JLabel label = new JLabel("Test");

    @Override
    public Component getListCellRendererComponent(JList list, Object value,
            int index, boolean isSelected, boolean cellHasFocus) {

        Font tempFont = label.getFont();
        setFont(new Font((String) value, tempFont.getStyle(),
                tempFont.getSize()));

        setText((String) value);

        return this;
    }
}

问题在于,使用此渲染器时, JComboBox 在程序执行期间无响应。第一次单击组合框以显示列表时,列表加载需要几秒钟。第二次单击,立即显示列表。

The problem is that, when using this renderer, the JComboBox becomes unresponsive during program execution. The first time one clicks on the combobox to reveal the list, it takes a couple of seconds for the list to load. The second time one clicks, the list is instantly displayed.

如果有人评论该行

setFont(new Font((String) value, tempFont.getStyle(),tempFont.getSize()));

,组合框工作正常。

如何防止这种反应迟钝?

How can one prevent this unresponsiveness?

推荐答案

组合的内部结构会尝试动态查找首选大小。为此,它遍历列表中的所有项目,向渲染器提供项目以测量渲染组件的首选大小。

What happens is that the combo's internals try to find the preferred size dynamically. For doing so, it loops through all items in the list, feeds the renderer with the items to measure the rendering component's preferred size.

您可以通过设置prototypeValue来防止这种情况。测量,然后使用该原型测量一次大小

You can prevent that by setting a prototypeValue for measuring, then the size is measured once using that prototype

 comboBox.setPrototypeDisplayValue(sampleFont);

编辑:当检测到@Boro时,这还不够 - 它只设置了comboBox本身的原型,不是弹出窗口中的列表(因为它应该,可能是疯狂的马车......)为了解决问题,我们必须手动设置它,这里是一个代码片段,用于播放

as @Boro detected, that's not enough - it sets the prototype for the comboBox itself only, not for the list in the popup (as it should, how crazily buggy can that ... possibly be). To hack around, we have to manually set it, here's a code snippet to play with

public class ComboWithPrototype {

    private JComponent createContent() {
        final Font[] systemFonts = GraphicsEnvironment
                .getLocalGraphicsEnvironment().getAllFonts();

        final JComboBox box = new JComboBox();
        box.setRenderer(new ComboBoxRenderer());
        box.setPrototypeDisplayValue(systemFonts[0]);
        Accessible a = box.getUI().getAccessibleChild(box, 0);
        if (a instanceof javax.swing.plaf.basic.ComboPopup) {
            JList popupList = ((javax.swing.plaf.basic.ComboPopup) a).getList();
            // route the comboBox' prototype to the list
            // should happen in BasicComboxBoxUI
            popupList.setPrototypeCellValue(box.getPrototypeDisplayValue());
        }
        Action action = new AbstractAction("set model") {

            @Override
            public void actionPerformed(ActionEvent e) {
                box.setModel(new DefaultComboBoxModel(systemFonts));
            }
        };
        JComponent panel = new JPanel(new BorderLayout());
        panel.add(box);
        panel.add(new JButton(action), BorderLayout.SOUTH);
        return panel;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame("");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new ComboWithPrototype().createContent());
                frame.setLocationRelativeTo(null);
                frame.pack();
                frame.setVisible(true);
            }
        });
    }

自定义ListCellRenderer(略有改动,期待Font类型的项目)

Custom ListCellRenderer (slightly changed, to expect items of type Font)

private class ComboBoxRenderer extends DefaultListCellRenderer {

    private Font baseFont = new JLabel("Test").getFont();

    @Override
    public Component getListCellRendererComponent(JList list, Object value,
            int index, boolean isSelected, boolean cellHasFocus) {

        super.getListCellRendererComponent(list, value, index, isSelected,
                cellHasFocus);
        if (value instanceof Font) {

            Font font = (Font) value;
            setFont(new Font(font.getName(), baseFont.getStyle(), baseFont.getSize())); 
            setText(font.getName());
        }

        return this;
    }
}

这篇关于如何在使用自定义ListCellRenderer时防止JComboBox无响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆