Загружайте что-то только тогда, когда элемент JList виден

Я реализую 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 ответа

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

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

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

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

  • setFixedCellHeight(int)
  • setFixedCellWidth(int)

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

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