установить значок JList с помощью DefaultListCellRenderer?

Приведенный ниже код должен получить значок каталога по умолчанию из JFileChooser, а затем использовать этот значок в моем пользовательском списке «Последние каталоги», который предоставляется в качестве аксессуара к диалоговому окну JFileChooser. Может кто-нибудь объяснить, почему приведенный ниже код не работает (в частности, почему setIcon в DefaultListRenderer не работает), и скажите мне, как поместить значок рядом с каждым элементом в JList? Я бы предпочел не реализовывать свой собственный ListCellRenderer, если только это не единственный способ заставить эту работу работать.

import java.awt.*;
import java.io.File;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class Chooser extends JPanel {
   private static final String[] BUTTON_TEXTS = { "Hello", "Goodbye",
         "Hello Goodbye", "Adios", "This is a long String for WTF", "Hello",
         "Goodbye", "Hello Goodbye", "Adios", "This string WTF" };

   public Chooser(Icon icon) {
      this.setLayout(new BorderLayout());

      JPanel labelPanel = new JPanel(new BorderLayout());
      JLabel label = new JLabel("Recent Directories:");
      labelPanel.add(label, BorderLayout.LINE_START);
      labelPanel.setBackground(Color.LIGHT_GRAY);
      labelPanel.setBorder(new EmptyBorder(5, 10, 5, 0));

      DefaultListModel model = new DefaultListModel();
      JList list = new JList(model);
      DefaultListCellRenderer renderer = (DefaultListCellRenderer)list.getCellRenderer();
      renderer.setIcon(icon);

      for (String s : BUTTON_TEXTS) model.addElement(s);

      list.setBorder(new EmptyBorder(0, 5, 5, 0));
      list.addListSelectionListener(new ListSelectionListener() {
         public void valueChanged(ListSelectionEvent e) {
            // respond to selection here
         }
      });

      add(labelPanel, BorderLayout.PAGE_START);
      // add(new JScrollPane(buttonPanel), BorderLayout.CENTER);
      add(new JScrollPane(list), BorderLayout.CENTER);
   }

   public static void main(String[] args) {
      // TODO Auto-generated method stub
      JFileChooser fileChooser = new JFileChooser();
      Icon icon = fileChooser.getIcon(new File("."));

      /*JFrame frame = new JFrame();
      frame.setSize(100,100);
      JPanel temp = new JPanel();
      JLabel tlbl = new JLabel("picture");
      tlbl.setIcon(icon);
      temp.add(tlbl);
      frame.add(temp);
      frame.setVisible(true);*/

      Chooser c = new Chooser(icon);

      fileChooser.setAccessory(c);
      fileChooser.showOpenDialog(null);
   }

}

person KyleM    schedule 24.09.2011    source источник
comment
Эта ссылка показалась мне интересной в связи с вашим вопросом tips4java. wordpress.com/2008/12/18/icon-table-cell-renderer   -  person enthusiasticgeek    schedule 14.03.2013


Ответы (2)


DefaultListCellRenderer очищает значок всякий раз, когда вызывается его метод getListCellRendererComponent.

Вместо этого вы можете вмешаться в метод рендерера, создав подкласс DefaultListCellRenderer следующим образом:

list.setCellRenderer(new DefaultListCellRenderer() {
    @Override
    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
        JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
        label.setIcon(icon);
        return label;
    }
});
person Howard    schedule 25.09.2011

Выбор

Совет по использованию пользовательского средства визуализации ячеек, дополненный несколькими другими советами, относящимися к работе с объектами File и Icon в файле JList.

import java.awt.*;
import java.io.File;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.filechooser.FileSystemView;

public class Chooser extends JPanel {
    private static final File[] RECENT_DIRECTORIES = File.listRoots();

    public Chooser() {
        this.setLayout(new BorderLayout());

        JPanel labelPanel = new JPanel(new BorderLayout());
        JLabel label = new JLabel("Recent Directories:");
        labelPanel.add(label, BorderLayout.LINE_START);
        labelPanel.setBackground(Color.LIGHT_GRAY);
        labelPanel.setBorder(new EmptyBorder(5, 10, 5, 0));

        JList list = new JList(RECENT_DIRECTORIES);
        list.setCellRenderer(new DefaultListCellRenderer() {
            FileSystemView fsv = FileSystemView.getFileSystemView();
            @Override
            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
                JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
                if (value instanceof File) {
                    label.setIcon(fsv.getSystemIcon((File)value));
                }
                return label;
            }
        });

        list.setBorder(new EmptyBorder(0, 5, 5, 0));
        list.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                // respond to selection here
            }
        });

        add(labelPanel, BorderLayout.PAGE_START);
        add(new JScrollPane(list), BorderLayout.CENTER);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFileChooser fileChooser = new JFileChooser();

                Chooser c = new Chooser();

                fileChooser.setAccessory(c);
                fileChooser.showOpenDialog(null);
            }
        });
    }
}

Резюме

Вкратце, эти советы таковы:

  • Используйте пользовательский рендеринг ячеек (как упоминал Ховард)
  • Не используйте объекты String в JList для представления объектов File. Используйте File.
  • Используйте осмысленные имена для атрибутов класса. НАПРИМЕР. BUTTON_TEXTS -> RECENT_DIRECTORIES
  • Предоставьте File[] конструктору Jlist — нет необходимости перебирать массив и добавлять каждый элемент.
  • Используйте FileSystemView.getSystemIcon(File), чтобы обойти унылые значки, выплевываемые каждым PLAF. Экземпляры Icon в списке выглядят странно рядом со значками, используемыми в исходной левой панели (начиная с «1 Media» и т. д.). Они совпадали бы, если бы PLAF был установлен на системный PLAF. Дело в том, что FSV будет давать лучшие Icon вне зависимости от PLAF.
  • Запустите графический интерфейс на EDT.

Еще больше советов (это совет-а-палуза!), см. в графическом интерфейсе файлового браузера.


Я не понял совет про "PLAF" (тоже не знаю, что означает PLAF).

К счастью, Google делает. Попробуйте выполнить поиск по нему и выберите первую ссылку, в которой упоминается «Java» (здесь это вторая ссылка).

Я заметил, что значок папки, полученный в результате использования вашего кода, отличается от значка папки/каталога в JFileChooser. Значок JFC синий и выглядит более java-y. Вызов getIcon(), который я использовал в своем исходном коде, работает, но я не уверен, как тот же значок с вызовом, похожим на ваш (FileSystemView.getSystemIcon() или аналогичный)

Все значки, отображаемые на экране браузера файлов (FileBro) кадры были сделаны с использованием метода выбора файлов getIcon(), но они похожи на те, что в вашем примере были созданы FSV, верно? Причина, по которой они похожи на значки FSV, показанные на снимке экрана Metal, заключается в том, что PLAF был системным по умолчанию для FileBro («Windows» PLAF). Когда графический интерфейс использует «родной» PLAF для этой ОС, значки, возвращаемые для средства выбора файлов, совпадают со значками, возвращаемыми FSV.

Если вам нужны более конкретные ответы после некоторых исследований и внимательного изучения main() FileBro, чтобы увидеть, как он устанавливает PLAF, задавайте более конкретные вопросы.

person Andrew Thompson    schedule 25.09.2011
comment
Андрей, спасибо за все советы. Не понял совет про PLAF (тоже не знаю, что значит PLAF). Я заметил, что значок папки, полученный в результате использования вашего кода, отличается от значка папки/каталога в JFileChooser. Значок JFC синий и выглядит более java-y. Вызов getIcon(), который я использовал в своем исходном коде, работает, но я не уверен, как тот же значок с вызовом, похожим на ваш (FileSystemView.getSystemIcon() или аналогичный) - person KyleM; 26.09.2011