3

How do I set a background image to a JTextPane - some sort of a watermark.

I tried this option - creating a child class of JTextPane and use the paint method to draw the image. But then the text is displayed "below" the image than above.

Is there any "standard" or "well known" way to do this?

(BTW, I tried (something silly?) making the content type "text/html", and setting the image as the background image of a <div> but it did not help.)

Nivas
  • 18,126
  • 4
  • 62
  • 76
  • @Nivas: it's not silly but the default Java components that support HTML typically only support a subset of HTML 3.2. In addition to that, their HTML renderer is pathetically bad, underperforming and a memory hog. People who really need HTML in Java tend to use other APIs than the default ones. – SyntaxT3rr0r Mar 31 '10 at 06:45

3 Answers3

7

Here's a working example:

import javax.swing.*;
import java.awt.*;

public class ScratchSpace {

    public static void main(String[] args) {
        JFrame frame = new JFrame("");
        final MyTextPane textPane = new MyTextPane();
        frame.add(textPane);

        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private static class MyTextPane extends JTextPane {
        public MyTextPane() {
            super();
            setText("Hello World");
            setOpaque(false);

            // this is needed if using Nimbus L&F - see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6687960
            setBackground(new Color(0,0,0,0));
        }

        @Override
        protected void paintComponent(Graphics g) {
            // set background green - but can draw image here too
            g.setColor(Color.GREEN);
            g.fillRect(0, 0, getWidth(), getHeight());

            // uncomment the following to draw an image
            // Image img = ...;
            // g.drawImage(img, 0, 0, this);


            super.paintComponent(g);
        }
    }
}

The important things to note:

  1. your component must not be opaque... so setOpaque(false);

  2. override paintComponent(Graphics g), not paint.

  3. paint your background, with an image or drawing BEFORE calling super.paintComponent(g);

If you want to master this stuff, I recommend reading "Filthy Rich Clients", a book all about how to bend Swing to your will.

Steve McLeod
  • 51,737
  • 47
  • 128
  • 184
  • This works perfectly in the default look and feel, but when I set the L&F to nimbus, this does not work. Nothing happens. (even if i just use the background color part and not the image) Could there be any specific reason, or could this be a bug in Nimbus? – Nivas Mar 31 '10 at 10:30
  • @Nivas, I've added a work-around to the Nimbus problem: setBackground(new Color(0,0,0,0)); – Steve McLeod Mar 31 '10 at 10:59
  • Thanks! I was about to comment "This is related to http://stackoverflow.com/questions/613603/java-nimbus-laf-with-transparent-text-fields :-) – Nivas Mar 31 '10 at 13:01
  • I found that the image was getting "stronger" everytime the TextPane got focus... thought that this was because the repaint method was painting the image again and again. To solve this, I added g.clearRect(0, 0, getWidth(), getHeight()); as the first line to paintComponent... and it worked! – Nivas Mar 31 '10 at 13:25
1

Try changing the paint code to this.

  public void paint(Graphics g)
  {
        g.setXORMode(Color.white);
        g.drawImage(image,0, 0, this);
        super.paint(g);
  }

This would make your image to be painted before the text is rendered by the actual component's paint method.

Chandra Sekar
  • 10,683
  • 3
  • 39
  • 54
1

Hmm., put a background image to the JFrame/JPanel containg the JTextPane,.. and keep the JTextPane transparent to some level.

raj
  • 3,769
  • 4
  • 25
  • 43
  • A good idea, but i have other components on the same panel. Yes I can add a new panel *just* for this text pane, but somehow i dont want to add more components... – Nivas Mar 31 '10 at 08:28