ListCellRenderer中的ImageIcon很慢



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

然而,Renderer的getListCellRendererComponent(...)方法在它返回的JLabel上使用ImageIcon。图标是正确加载的,但是,当我第一次单击组合框时(每次运行时),图像需要恰好(或至少非常非常接近),加载时间比1秒多一点。我认为这是加载文件时的一些延迟,除了

    这是一个4kB的文件在我的本地文件系统
  • 当我在result.setIcon(...)命令之前和之后添加System.out.println命令时,它们几乎立即跟随对方。

我注意到的奇怪的事情是,println命令被触发两次,一次当我点击框,再次当图标加载。

还值得注意的是,由于这是设计用于覆盖父抽象类的单个方法的多个类(以生成图标的路径),当我注意到这工作缓慢时,我将代码从简单地使用getIcon命令检索图标更改为将各种大小的图标(16,32和64平方像素)存储在TreeMap<Tool.ImageSize, ImageIcon>中(其中Tool是我创建的具有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);
}

但是,当我第一次单击组合框时(每次运行时),图像需要一秒钟多一点的时间来加载。我认为这是加载文件

时的一些延迟。

这也是我的猜测。

除了当我在result.setIcon(…)命令之前和之后添加System.out.println命令时,它们几乎立即跟随对方

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

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

解决方案是在程序启动时加载图标。也就是说,无论何时你定义/添加图标到地图上,你都应该在那个时候读取它们。你可能想在一个单独的线程上做,这样你就不会阻止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。

相关内容

  • 没有找到相关文章

最新更新