ImageIcon работает медленно в ListCellRenderer - PullRequest
2 голосов
/ 11 сентября 2011

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

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

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

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

Также стоит отметить, что это разработано для работы с несколькими классами, которые переопределяют один метод родительского абстрактного класса (для генерации пути к иконке).Когда я заметил, что это работает медленно, я изменил код с простого извлечения значка с помощью команды getIcon на хранение значков различных размеров (16, 32 и 64 px в квадрате) в TreeMap<Tool.ImageSize, ImageIcon> (где * 1030)* это интерфейс, который я создал и который имеет метод 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 для получения изображения path ) и поскольку метод работает (он получает путь в порядке, просто значок загружается медленно), я не включил этот класс.

Класс 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 Ответ

3 голосов
/ 11 сентября 2011

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

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

за исключением того, что когда я добавляю команды 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 , который демонстрирует проблему.

...