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.
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.