Загружайте что-то только тогда, когда элемент JList виден - PullRequest
3 голосов
/ 02 ноября 2009

Я реализую Jlist, заполненный множеством элементов. Каждый элемент соответствует изображению, поэтому я хотел бы показать их предварительный просмотр в каждой строке списка. Я реализовал пользовательский ImageCellRenderer , расширяющий Jlabel, и getListCellRendererComponent я создаю миниатюру, если ее нет для этого элемента. Каждая строка соответствует классу Page , где я храню путь к изображению и значок, примененный к JLabel. Каждый Page объект помещается в DefaultListModel для заполнения JList. Код рендеринга выглядит примерно так:

        public Component getListCellRendererComponent(
            JList list,
            Object value,
            int index,
            boolean isSelected,
            boolean cellHasFocus)
    {
        Page page = (Page) value;

        if (page.getImgIcon() == null)
        {
            System.out.println(String.format("Creating thumbnail of %s", page.getImgFilename()));
            ImageIcon icon = new ImageIcon(page.getImgFilename());

            int thumb_width = icon.getIconWidth() > icon.getIconHeight() ? 128 : ((icon.getIconWidth() * 128) / icon.getIconHeight());
            int thumb_height = icon.getIconHeight() > icon.getIconWidth() ? 128 : ((icon.getIconHeight() * 128) / icon.getIconWidth());
            icon.setImage(getScaledImage(icon.getImage(), thumb_width, thumb_height));

            page.setImgIcon(icon);
        }

        setIcon(page.getImgIcon());

    }

Я думал, что в Списке виден только определенный элемент, который называется средством визуализации ячеек, но я вижу, что все thumnails создаются, когда я добавляю объект Page в модель списка. Я пытался загрузить элементы и после установки модели в JList или сначала установить модель и после начала добавления элементов, но результаты совпадают. Есть ли способ загрузить данные только тогда, когда это необходимо, или мне нужно создать пользовательский элемент управления, например JScrollPanel, со сложенными элементами внутри, где я сам проверяю видимость каждого элемента?

Спасибо

Ответы [ 2 ]

3 голосов
/ 02 ноября 2009

Я считаю, что JList просматривает все элементы и вызывает средство визуализации, чтобы определить предпочтительный размер списка.

Вы можете предотвратить это, используя метод setPrototypeCellValue (...). Конечно, средство визуализации будет по-прежнему вызываться для всех элементов, видимых на панели прокрутки.

1 голос
/ 03 ноября 2009

Виновным представляется BasicListUI в его updateLayoutState(). Во время операции рисования он будет перебирать все элементы в вашем dataModel, когда установлен флаг updateLayoutStateNeeded (который устанавливается после, казалось бы, каждого изменения свойства, а также когда интервалы добавляются и удаляются из * 1005). *). В каждой из ячеек он вызовет метод getListCellRendererComponent и заставит вас загрузить иконку. Вы можете остановить это, если вы установите поля fixedCellHeight и fixedCellWidth в своем экземпляре JList.

Вы можете попытаться установить фиксированную высоту и ширину с помощью двух открытых методов:

  • setFixedCellHeight(int)
  • setFixedCellWidth(int)

В качестве отступления: в общем случае загрузка значков из файловой системы может быть медленной и приводить к замедлению работы вашего графического интерфейса при выполнении в потоке диспетчеризации событий. Обычно это больше проблема с большими изображениями, где загрузка файла может занять некоторое время. Возможно, вы захотите, если вы еще этого не сделали, рассмотреть возможность загрузки значков в отдельном потоке. Это можно сделать, имея общий «значок недоступного изображения», который вы загружаете сразу, и когда ваш Page запрашивает значок, если значок для конкретной страницы имеет значение NULL, вы можете инициировать загрузку нужного файла, а затем верните 'значок недоступного изображения', и после загрузки Page назначьте его экземпляру Page и запустите перерисовку. Просто мысль.

...