1

I have a component extends JPanel. It saves itself as bufferedimage on every call of paintComponent method. Component is not completely transparent, only its background. Problem is background is not transparent. I am using setOpaque(false);

Here is my relevant code;

private BufferedImage bufImage = null;

public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D)g;

    // if first time call
    if (bufImage == null) {
        int w = this.getWidth();
        int h = this.getHeight();
        bufImage = (BufferedImage)this.createImage(w, h);
    }

    g2.drawImage(bufImage, null, 0, 0);

    // draw sth
    g2.draw(sth);
}

--

I also tried

bufImage =  new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);

instead of

bufImage = (BufferedImage)this.createImage(w, h);

When i do that; background transperancy works but i can only draw with white color. I have no idea what causes that.

Note: I used that code to check if it is working;

File outputfile = new File("saved.png");
ImageIO.write(bufImage, "png", outputfile);

saved.png had transparent background but drawings were only white.


This is the component, only lets drawing rectangle with mouse;

class PaintPanel extends JPanel implements MouseListener, MouseMotionListener {
    private BufferedImage _bufImage = null;
    private boolean dragging = false;
    private Point _start = null, _end = null;

    public PaintPanel() {
        setOpaque(false);
        this.addMouseListener(this);
        this.addMouseMotionListener(this);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D)g;

        if (_bufImage == null) {
            int w = this.getWidth();
            int h = this.getHeight();
            _bufImage =  new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
            //_bufImage = (BufferedImage)this.createImage(w, h);
        }

        g2.drawImage(_bufImage, null, 0, 0);

        if (dragging) {
            drawCurrentShape(g2);
        }
    }

    private void drawCurrentShape(Graphics2D g2) {
        int startx = (int) _start.getX();
        int starty = (int) _start.getY();
        int stopx = (int) _end.getX();
        int stopy = (int) _end.getY();

        int width = Math.abs(startx - stopx);
        int height = Math.abs(starty - stopy);
        int x = startx, y = starty;
        if(x > stopx)
            x = stopx;
        if(y > stopy)
            y = stopy;

        Rectangle r = new Rectangle(x, y, width, height);
        g2.draw(r);
    }

    public void mousePressed(MouseEvent e) {
        dragging = true;       
        _start = e.getPoint();
        _end   = _start;
    }

    public void mouseDragged(MouseEvent e) {
        _end = e.getPoint();
        this.repaint();
    }

    public void mouseReleased(MouseEvent e) {
        _end = e.getPoint();
        if (dragging) {
            dragging = false;
            drawCurrentShape(_bufImage.createGraphics());  
            this.repaint();
        }
    }

    public void mouseMoved  (MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited (MouseEvent e) {}
    public void mouseClicked(MouseEvent e) {}
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
previous_developer
  • 10,579
  • 6
  • 41
  • 66
  • I don't think creating a BufferedImage automatically makes it transparent. You still need to paint the background with a tranparent color by using the `fillRect(...)` method. Post your SSCCE if you need more help. – camickr Feb 13 '12 at 18:31
  • 2 things, you should use print() to create the image and you should not create the image inside the paintComponent. Print is almost the same as paint() but it turns on/off some flags. Therefore using paint-->will not work. Using print inside paintComponent-->will not work because you are already inside the paint method which will prevent setting up the print flags. See my answer below. – Guillaume Polet Feb 13 '12 at 19:49
  • I saw your answer but i couldn't understand why my way is wrong. It is working now but what kind of problem this can cause in the future? I used this project as a base; http://www.leepoint.net/notes-java/examples/mouse/paintdemo.html . Because of letting user to draw, i must repaint after every movement and save that. I thought this is a good way. How can i do that under circumstances you said? – previous_developer Feb 14 '12 at 01:45

2 Answers2

2

try this:

bufImage = new BufferedImage(w,h,java.awt.image.BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = bufImage.createGraphics();
this.print(graphics);
graphics.dispose();

The key is to use print()

Edit: I tried the following and transparency works like a charm:

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Test2 {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        final JPanel p = new JPanel();
        p.setPreferredSize(new Dimension(400, 400));
        p.setOpaque(false);
        JButton button = new JButton("Hello world");
        p.add(button);
        frame.add(p);
        frame.pack();
        frame.setVisible(true);
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                BufferedImage bufImage = new BufferedImage(p.getWidth(), p.getHeight(), java.awt.image.BufferedImage.TYPE_INT_ARGB);
                Graphics2D graphics = bufImage.createGraphics();
                p.print(graphics);
                graphics.dispose();
                try {
                    ImageIO.write(bufImage, "png", new File("d:/tmp/tmp.png"));
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
    }
}
Guillaume Polet
  • 47,259
  • 4
  • 83
  • 117
1

createImage(w, h) will create a "blank" image with the specified width and height. That being said, what you'll need to do is invoke createGraphics on the BufferedImage instance and draw directly to the returned Graphics object.

mre
  • 43,520
  • 33
  • 120
  • 170