Can not draw image on JTextArea background when us

2019-02-25 18:59发布

问题:

I am drawing an image on JTextArea background, it is drawn using other look and feels (Metal, Windows etc) but when I use Nimbus Look And Feel it does not draw image What can be the possible problem and how to fix that? Here is the code I am using

Image TextArea Class

public class ImageTextArea extends JTextArea{
    File image;
    public ImageTextArea(File image)
    {
        setOpaque(false);
        this.image=image;
    }

    @Override
    public void paintComponent(final Graphics g)
    {
        try
        {
            // Scale the image to fit by specifying width,height
            g.drawImage(new ImageIcon(image.getAbsolutePath()).getImage(),0,0,getWidth(),getHeight(),this);
            super.paintComponent(g);
        }catch(Exception e){}
    }
}

And the Test class

public class TestImageTextArea extends javax.swing.JFrame {

    private ImageTextArea tx;

    public TestImageTextArea() {
        tx = new ImageTextArea(new File("img.jpg"));
        setTitle("this is a jtextarea with image");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        JPanel mainp = new JPanel(new BorderLayout());
        add(mainp);
        mainp.add(new JScrollPane(tx), BorderLayout.CENTER);
        setSize(400, 400);
    }

    public static void main(String args[]) {
/*
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (Exception ex) {
            System.out.println("Unable to use Nimbus LnF: "+ex);
        }
*/
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                new TestImageTextArea().setVisible(true);
            }
        });
    }

}

When I remove the comments it does not draw image.

回答1:

Basically, when you call super.paintComponent, it will call the UI delgate's update method. This is where the magic happens.

Below is the Nimbus's SynthTextAreaUI implementation

public void update(Graphics g, JComponent c) {
    SynthContext context = getContext(c);

    SynthLookAndFeel.update(context, g);
    context.getPainter().paintTextAreaBackground(context,
                      g, 0, 0, c.getWidth(), c.getHeight());
    paint(context, g);
    context.dispose();
}

As you can see, it actually paints the background, with out regard for the opaque state of the component, then calls paint, which will call the BasicTextUI.paint method (via super.paint)

This is important, as BasicTextUI.paint actually paints the text.

So, how does that help us? Normally, I'd crucify someone for not calling super.paintComponent, but this is exactly what we're going to do, but we're going to do it knowing in advance what responsibility we're taking on.

First, we're going to take over the responsibilities of update, fill the background, paint our background and then call paint on the UI delegate.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class NimbusTest {

    public static void main(String[] args) {
        new NimbusTest();
    }

    public NimbusTest() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new JScrollPane(new TestTextArea()));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestTextArea extends JTextArea {

        private BufferedImage bg;

        public TestTextArea() {
            try {
                bg = ImageIO.read(new File("C:\\Users\\swhitehead\\Documents\\My Dropbox\\Ponies\\Rainbow_Dash_flying_past_3_S2E16.png"));
            } catch (IOException ex) {
                Logger.getLogger(NimbusTest.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        @Override
        protected void paintComponent(Graphics g) {
            Graphics2D g2d = (Graphics2D) g.create();
            // Fill the background, this is VERY important
            // fail to do this and you will have major problems
            g2d.setColor(getBackground());
            g2d.fillRect(0, 0, getWidth(), getHeight());
            // Draw the background
            g2d.drawImage(bg, 0, 0, this);
            // Paint the component content, ie the text
            getUI().paint(g2d, this);
            g2d.dispose();
        }

    }
}

Make no mistake. If you don't do this right, it will screw not only this component but probably most of the other components on your screen.