java - ListCellRenderer 中的 ImageIcon 速度缓慢

标签 java performance jcombobox imageicon listcellrenderer

我有一个class GridPanel extends JPanel ,具有静态内部类 ToolSelectComboBox extends JComboBox ,它又具有两个静态内部类 ToolSelectComboBoxModel implements ComboBoxModelToolSelectComboBoxRenderer implements ListCellRenderer 。面板显示ToolSelectComboBox (TSCB),其构造函数将其模型和渲染器设置为我创建的自定义模型和渲染器。盒子已正确创建,并且其模型和渲染器工作正常。

但是,渲染器的 getListCellRendererComponent(...)方法使用 ImageIcon关于JLabel它返回。图标已正确加载,但是,第一次单击组合框(每次运行)时,图像加载需要完全(或至少非常非常接近)一秒多一点。我认为这是加载文件的一些滞后,除了

  • 这是我本地文件系统上的一个 4kB 文件
  • 当我添加System.out.printlnresult.setIcon(...) 之前和之后的命令一旦发出命令,他们几乎立即相互跟随。

我注意到的奇怪的事情是 println命令被触发两次,一次是在我单击该框时,另一次是在图标加载时。

还值得注意的是,由于它设计用于与覆盖父抽象类的单个方法的多个类一起使用(以生成图标的路径),当我注意到它运行缓慢时,我改变了简单地使用 getIcon 检索图标的代码命令将各种大小的图标(16、32 和 64 像素平方)存储在 TreeMap<Tool.ImageSize, ImageIcon> 中(其中 Tool 是我创建的一个接口(interface),它具有 ImageIcon getIcon() 方法。

我所有的进口都是有序的。

如有任何帮助,我们将不胜感激!

如果我发布了太多代码,我深表歉意,但我想确保它是可以理解的。另一方面,如果您需要更多代码才能理解,请随时询问。

代码(所有以“* ”开头且具有类似注释文本的行都是折叠的 JavaDoc 标记,而不仅仅是困惑的代码):

public class GridPanel extends JPanel {

    public static class ToolSelectComboBox extends JComboBox {

         // Combo box model `ToolSelectComboBoxModel` snipped

         * A renderer for the {@link ToolSelectComboBoxModel}. This may
        public static class ToolSelectComboBoxRenderer implements
                ListCellRenderer {

             * The default renderer. Only the icon and text are modified.
            protected DefaultListCellRenderer d = new DefaultListCellRenderer();

            @Override
            public Component getListCellRendererComponent(final JList list,
                    final Object value, final int index,
                    final boolean isSelected, final boolean cellHasFocus) {
                if (!ToolSelectComboBoxModel.class.isInstance(list.getModel())) {
                    throw new IllegalStateException(
                            "Cannot use a ToolSelectComboBoxRenderer on any list model type other than ToolSelectComboBoxModel.");
                }
                final JLabel result = (JLabel) d.getListCellRendererComponent(
                        list, value, index, isSelected, cellHasFocus);
                result.setText(null);
                if (value != null) {
                    result.setIcon(((Tool) value)
                            .getIcon(Tool.IconSize.SIZE_32PX));
                }
                return result;
            }
        }

        public ToolSelectComboBox() {
            setModel(new ToolSelectComboBoxModel());
            ((ToolSelectComboBoxModel) getModel()).add(new CircleTool()); // shown below
            setRenderer(new ToolSelectComboBoxRenderer());
        }
    }

     * Create the panel.
    public GridPanel() {
        setLayout(new BorderLayout(0, 0));

        final ToolSelectComboBox toolSelectComboBox = new ToolSelectComboBox();
        add(toolSelectComboBox, BorderLayout.NORTH);

        final SquareGrid squareGrid = new SquareGrid(); // another class; this works fine
        add(squareGrid, BorderLayout.CENTER); // irrelevant to problem

    }

}

CircleTool类只有一个方法(覆盖 AbstractTool 的抽象方法来获取图像路径),并且由于该方法有效(它可以很好地获取路径,只是加载缓慢的图标),我没有包含这个类。

AbstractTool类:

public abstract class AbstractTool implements Tool {

    /**
     * A {@link TreeMap} to map the icon sizes to their icons.
     */
    protected final TreeMap<Tool.IconSize, ImageIcon> map = new TreeMap<Tool.IconSize, ImageIcon>();

    /**
     * Constructs the tool and sets up the {@linkplain #map}.
     */
    public AbstractTool() {
        for (final Tool.IconSize size : Tool.IconSize.values()) {
            System.out.println("Putting value for " + size);
            map.put(size,
                    new ImageIcon(Tool.class.getResource(getImagePath(size))));
        }
    }

    @Override
    public ImageIcon getIcon(final IconSize size) {
        return map.get(size);
    }

    /**
     * Gets the image path for the given image size.
     * 
     * @param size
     *            the size
     * @return the image path
     */
    protected abstract String getImagePath(Tool.IconSize size);

}

最佳答案

but, the first time I click the combo box (on each run), the image takes a little more than a second to load. I would assume that this is some lag in loading the file

这也是我的猜测。

except that when I add System.out.println commands before and after the result.setIcon(...) command, they follow each other almost instantly

当您单击组合框时,所有代码都会在 EDT 上运行,这意味着每个图标都会按顺序加载。

但是 System.out.println() 在单独的线程上运行,因此它会立即显示。

解决方案是在程序启动时加载图标。也就是说,每当您定义/添加图标到 map 时,您都应该在那时读取它们。您可能希望在单独的线程上执行此操作,这样就不会阻止 GUI 显示。

编辑:

这是一个简单的 SSCCE,它在组合框中显示图标:

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

public class ComboBoxIcon extends JFrame
{
    JComboBox comboBox;

    public ComboBoxIcon()
    {
        Object[] items =
        {
            new ImageIcon("about16.gif"),
            new ImageIcon("add16.gif"),
            new ImageIcon("copy16.gif")
        };
        comboBox = new JComboBox( items );
        getContentPane().add( comboBox, BorderLayout.NORTH );
    }

    public static void main(String[] args)
    {
        JFrame frame = new ComboBoxIcon();
        frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible( true );
    }
}

如果您需要更多帮助,那么您需要发布您的SSCCE这说明了问题。

关于java - ListCellRenderer 中的 ImageIcon 速度缓慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7379914/

相关文章:

java - 从数据库中的预定义值列表中存储值的最佳方法是什么?

java - 添加触摸事件监听器到android Canvas

performance - 在 Travis CI 上缓存 docker 图像

jquery - DOMContentLoaded 在 Chrome 中非常慢

java - 如何使用 Map 元素作为 JComboBox 的文本

java - pc 到手机聊天使用蓝牙?

java - 谷歌应用程序引擎远程API用于本地开发服务器重定向到登录页面

R:提高数据框中每一行的 t 检验速度

java - 从 JComboBox 的监听器中移除元素

java - 如何使用 jtextfield 在 jcombo 框自动建议中接受小写和大写