ImageIcon работает медленно в ListCellRenderer

У меня есть class GridPanel extends JPanelсо статическим внутренним классом ToolSelectComboBox extends JComboBoxкоторый в свою очередь имеет два статических внутренних класса ToolSelectComboBoxModel implements ComboBoxModel а также ToolSelectComboBoxRenderer implements ListCellRenderer, Панель отображает ToolSelectComboBox (TSCB), конструктор которого устанавливает свою модель и средство визуализации в качестве пользовательских, которые я создал. Коробка создана правильно, а ее модели и рендеры работают корректно.

Тем не менее, рендерер getListCellRendererComponent(...) Метод использует ImageIcon на JLabel что он возвращается. Значок загружается правильно, но при первом нажатии на поле со списком (при каждом запуске) изображение загружается ровно (или, по крайней мере, очень близко) немного больше секунды. Я бы предположил, что это некоторая задержка в загрузке файла, за исключением того, что

  • Это файл 4 КБ в моей локальной файловой системе
  • Когда я добавлю System.out.println Команды до и после result.setIcon(...) команды, они следуют друг за другом почти мгновенно.

Странная вещь, которую я замечаю, это то, что println Команды запускаются дважды, один раз, когда я нажимаю на поле, и снова, когда загружается значок.

Также стоит отметить, что, поскольку это предназначено для работы с несколькими классами, которые переопределяют один метод родительского абстрактного класса (для генерации пути к значку), когда я заметил, что это работает медленно, я изменил код просто получить значок с getIcon команда для хранения значков различных размеров (квадраты 16, 32 и 64 px) в 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);

}

1 ответ

Решение

но, когда я впервые щелкаю поле со списком (при каждом запуске), загрузка изображения занимает чуть больше секунды. Я бы предположил, что это некоторая задержка в загрузке файла

Это было бы и мое предположение.

за исключением того, что когда я добавляю команды System.out.println до и после команды result.setIcon (...), они почти мгновенно следуют друг за другом

Когда вы нажимаете на поле со списком, весь код запускается в EDT, что означает, что каждый значок будет загружен последовательно.

Однако System.out.println() выполняется в отдельном потоке, поэтому он отображается немедленно.

Решением является загрузка значков при запуске программы. То есть всякий раз, когда вы определяете / добавляете значки на карту, вы должны прочитать их в это время. Вы можете сделать это в отдельном потоке, чтобы не блокировать отображение графического интерфейса.

Редактировать:

Вот простой 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, который демонстрирует проблему.

Другие вопросы по тегам