Adding a JTable background image that does not scroll

Make sure all your internal JTable components have the opaqueness property set to false. Setting the JTable opaque property to false won’t work as the table is added to a JScrollPane. Extend the JScrollPane class and override the paint method to paint the image every time an event occurs where a repainting is necessary.

Main.java:

import javax.swing.table.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
 
public class Main extends JFrame
{
   public Main() {
      JTable table = new JTable(100, 5) {
         public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
            Component c = super.prepareRenderer(renderer, row, column);
            if (c instanceof JComponent) {
                ((JComponent) c).setOpaque(false);
            }
            return c;
         }
      };
 
      ImageJScrollPane isp = new ImageJScrollPane(table);
 
      isp.setBackgroundImage(new ImageIcon("c:\mong.jpg"));
 
      getContentPane().add(isp);
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(0);
         }
      });
   }
 
   public static void main(String [] args) {
      Main main = new Main();
      main.setSize(400, 400);
      main.setVisible(true);
   } 
} 
 
class ImageJScrollPane extends JScrollPane 
{
   private ImageIcon image = null;
 
   public ImageJScrollPane() {
      this(null, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED);
   }
 
   public ImageJScrollPane(Component view) {
      this(view, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED);
   }
   
   public ImageJScrollPane(Component view, int vsbPolicy, int hsbPolicy) {
      super(view, vsbPolicy, hsbPolicy);
      if (view instanceof JComponent) {
         ((JComponent) view).setOpaque(false);
      }
   }
 
   public ImageJScrollPane(int vsbPolicy, int hsbPolicy) {
      this(null, vsbPolicy, hsbPolicy);
   }
 
   public void setBackgroundImage(ImageIcon image) {
      this.image = image;
   }
 
   public void paint(Graphics g) {
      // Do not use cached image for scrolling
      getViewport().setBackingStoreEnabled(false);
 
      if (image != null) {
         Rectangle rect = getViewport().getViewRect();
         for (int x=0; x<rect.width; x+=image.getIconWidth()) {
            for (int y=0; y<rect.height; y+=image.getIconHeight()) {
               g.drawImage(image.getImage(), x, y, null, null); 
            }
         }
 
         super.paint(g);
      }
   }
}

Here’s the image I used: