set JList icon with DefaultListCellRenderer?
The code below is supposed to get the default directory icon from the JFileChooser and then use that icon in my custom "Recent Directories" list which is provided as an accessory to the JFileChooser dialog. Can someone please explain why the below code does not work (particularly why setIcon on the DefaultListRenderer doesn't do the trick), and tell me how to put the icon next to each item in the JList? I would prefer to avoid implementing my own ListCellRenderer unless that is the only way to make this work.
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开发者_StackOverflow:");
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);
}
}
The DefaultListCellRenderer
clears the icon whenever its getListCellRendererComponent
method is called.
Instead you can interfere with the renderer's method by subclassing DefaultListCellRenderer
like that:
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;
}
});
The tip of using a custom cell renderer, extended to include a few other tips specific to dealing with File
and Icon
objects in a 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);
}
});
}
}
Summary
In summary, those tips are:
- Use a custom cell renderer (as mentioned by Howard)
- Don't use
String
objects in theJList
to representFile
objects. Use theFile
. - Use meaningful names for the class attributes. E.G.
BUTTON_TEXTS
->RECENT_DIRECTORIES
- Provide the
File[]
to the constructor of theJlist
- there is no need to iterate the array and add each item. - Use
FileSystemView.getSystemIcon(File)
to get around the dull icons spat out by each PLAF. TheIcon
instances in the list look odd beside the icons used in the original left hand pane (starting with "1 Media" etc.). They would match if the PLAF were set to the system PLAF. The point is that FSV will provide the nicerIcon
regardless of PLAF. - Start the GUI on the EDT.
For even more tips (it's tip-a-palooza!), see File Browser GUI.
I did not understand the tip about "PLAF" (I also don't know what PLAF means).
Lucky Google does. Try searching on it and select the first link that mentions 'Java' (here it is the 2nd link).
I did notice that the folder icon that results from using your code is different than the folder/directory icon on the JFileChooser. The JFC's icon is blue and look more java-y. The getIcon() call that I used in my original code does work but I'm not sure how the same icon with a call similar to yours (FileSystemView.getSystemIcon() or similar)
All the icons seen in the File Browser (FileBro) GUI screen shot were made using the file chooser getIcon()
method, but they look like the ones in your example that were produced by the FSV, right? The reason they look like the FSV icons seen in the Metal screenshot is that the PLAF was the system default for FileBro ('Windows' PLAF). When a GUI uses the 'native' PLAF for that OS, the icons returned for the file chooser match those returned by the FSV.
If you need more specific answers after doing some research and looking closely at the main()
of FileBro to see how it sets the PLAF, ask more specific questions.
精彩评论