使用DefaultListCellRenderer设置JList图标?

时间:2011-09-24 22:48:24

标签: java swing jfilechooser

下面的代码应该从JFileChooser获取默认目录图标,然后在我自定义的“Recent Directories”列表中使用该图标,该列表作为JFileChooser对话框的附件提供。有人可以解释为什么下面的代码不起作用(特别是为什么在DefaultListRenderer上的setIcon没有做到这一点),并告诉我如何将图标放在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);
   }

}

2 个答案:

答案 0 :(得分:7)

只要调用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;
    }
});

答案 1 :(得分:4)

Chooser

使用自定义单元格渲染器的提示,扩展为包含一些特定于处理FileIconJList个对象的其他提示。

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);
            }
        });
    }
}

摘要

总之,这些提示是:

  • 使用自定义单元格渲染器(如Howard所述)
  • 请勿在{{1​​}}中使用String个对象来表示JList个对象。使用File
  • 为类属性使用有意义的名称。例如。 File - > BUTTON_TEXTS
  • RECENT_DIRECTORIES提供给File[]的构造函数 - 无需迭代数组并添加每个项目。
  • 使用Jlist绕过每个PLAF吐出的沉闷图标。列表中的FileSystemView.getSystemIcon(File)个实例在原始左侧窗格中使用的图标旁边看起来很奇怪(以“1 Media”等开头)。如果将PLAF设置为系统PLAF,它们将匹配。重点是FSV将提供更好的Icon,无论PLAF如何。
  • 在EDT上启动GUI。

如需更多提示(这是tip-a-palooza!),请参阅File Browser GUI


  

我不明白关于“PLAF”的提示(我也不知道PLAF是什么意思)。

幸运谷歌。尝试搜索并选择第一个提到“Java”的链接(这里是第二个链接)。

  

我注意到使用代码产生的文件夹图标与JFileChooser上的文件夹/目录图标不同。 JFC的图标是蓝色的,看起来更像是java-y。我在原始代码中使用的getIcon()调用确实有效,但我不确定调用类似于你的相同图标(FileSystemView.getSystemIcon()或类似的)

所有 File Browser (FileBro) GUI屏幕截图中显示的图标都是使用文件选择器Icon方法制作的,但它们看起来就像您示例中由FSV,对吗?它们看起来像金属屏幕截图中看到的FSV图标的原因是PLAF是FileBro('Windows'PLAF)的系统默认值。当GUI使用该OS的“本机”PLAF时,为文件选择器返回的图标与FSV返回的图标匹配。

如果您在进行一些研究后需要更具体的答案,并仔细查看FileBro的getIcon()以了解它如何设置PLAF,请提出更具体的问题。