Ever wanted to use an image as a background of your JList component? Unfortunately the Swing library does not provide a simple method to set a image as a background. In order to do so, you are force to do some custom painting inside the paintComponent method. In the case of a JList, our custom painting has to be performed inside a custom implementation of a ListCellRenderer. Check out the video below to see it in action.
A Custom ListCellRenderer
As stated before, we need to create a custom ListCellRenderer implementation and perform our own painting of the background image. Since ListCellRenderer only paints each element of a list, we need to perform a trick in order to make the background image appear stationary even when you are scrolling the list.
The trick
The trick to making the background image stationary is to dynamically calculate the offset of the image relative to the renderer and draw a portion of the image that will appear under the renderer.
The complete working code below is ready to use in your programs.
public class BackgroundImageListCellRenderer extends DefaultListCellRenderer {
int row = -1;
private JList list;
private final Image image;
private JScrollPane scrollPane;
public BackgroundImageListCellRenderer(JScrollPane scrollPane, Image image) {
this.image = image;
this.scrollPane = scrollPane;
// must use SIMPLE_SCROLL_MODE to force scrollpane to redraw the whole JList,
// otherwise scrollpane will use 'cached' images
scrollPane.getViewport().setScrollMode(JViewport.SIMPLE_SCROLL_MODE);
// we will paint our own background
setOpaque(false);
}
public Component getListCellRendererComponent(JList list, Object value, int row, boolean isSelected, boolean cellHasFocus) {
this.list = list;
this.row = row;
return super.getListCellRendererComponent(list, value, row, isSelected, cellHasFocus);
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
// compute the offset of the image we want to draw
Rectangle cellBounds = list.getCellBounds(row, row);
Point p = cellBounds.getLocation();
Point viewPosition = scrollPane.getViewport().getViewPosition();
p.x -= viewPosition.x;
p.y -= viewPosition.y;
// draw the image from the offset computed above
AffineTransform transform = AffineTransform.getTranslateInstance(-p.x, -p.y);
g2d.drawImage(image, transform, null);
// let the original renderer do its work
super.paintComponent(g);
}
}
Creating the demo
Below is the main program that I used to create the JList GUI in the demo video. I loaded the background image from a file and initialize the custom cell renderer with it.
public static void main(String args[]) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Image img = Toolkit.getDefaultToolkit().getImage(ListWithImageBackground.class.getResource("Rocks.jpg"));
MediaTracker tracker = new MediaTracker(f);
tracker.addImage(img, 0);
try {
tracker.waitForAll();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
final MyListModel listModel = new MyListModel();
for(int i=1; i <= 100; i++ ) {
listModel.addElement("Item " + i);
}
JList list = new JList(listModel);
list.setFont(new Font("Arial", Font.BOLD, 36));
JScrollPane sp = new JScrollPane(list);
BackgroundImageListCellRenderer renderer = new BackgroundImageListCellRenderer(sp, img);
renderer.setHorizontalAlignment(JLabel.CENTER);
list.setCellRenderer(renderer);
f.add(sp, BorderLayout.CENTER);
f.setSize(640, 480);
f.setVisible(true);
}
Related posts:
Hi Jim,really great work but i wonder if you know how to add image to each item in the jlist.As i have jlist carrying the name of clients and i want to add an image beside each name to determine whether the user is connected or disconnected.Any hints? Thanks in advance.
Fatema, take a look at this page. The key idea is in your getListCellRendererComponent(…) method of your ListCellRenderer implementation, you need to set the icon (which can be a image if you use ImageIcon). If all you need is to produce a image and text alongside it, then you can extend DefaultListCellRenderer. DefaultListCellRenderer uses JLabel to do the rendering and this is why you can set the icon image. If you want more complex layout, then you can create the JPanel with your preferred LayoutManager.