Is it possible to have multiple independent drawing layers using Graphics
? I actually need two layers (like in Photoshop, Gimp, Paint.NET, ...) on which I can draw objects and I want all objects of the top layer appear above all objects of the bottom layer, independent of the order in which objects are drawn. It is not the case that I can first draw all objects of one layer and then draw all objects of the other.
Example:
- draw red filled circle on bottom layer
- draw green rectangle on top layer
- draw red filled rectangle on bottom layer
- draw green circle on top layer
Desired result: the two empty green objects should be rendered above the two filled red objects.
I fiddled around using JLayeredPane
and Canvas
and the closest I could get was a Canvas
on top of a JComponent
but unfortunately the Canvas
background cannot be transparent, so everything that is drawn in the JComponent
is covered by the Canvas
background.
Can you tell me how to achieve this (if it's possible after all)?
There are a few ways to do it. You can keep a list of BufferedImages as your layers of images and render them accordingly:
class AdvancePaint extends JPanel(){
ArrayList<BufferedImage> layers;
//Other constructors, variables, initializations not shown
class AdvancePaint(){
layers = new ArrayList<BufferedImage>();
}
public void addLayer(BufferedImage layer){
layers.add(layer);
}
@Override
public void paintComponent(Graphics g){
super.paintComponent(g);
for(BufferredImage buf : layers) //render all layers
g.drawImage(buf, 0, 0, width, height, null);
}
}
The above codes will render the BufferedImage from the list in accordance to the order they are added to the list. If you do not want to paint all layers on every repaint, you can always add another draw(Graphics g)
method which you can pick the layers to be drawn onto another BufferedImage. Then only draw this BufferedImage on paintComponent(g)
.
Since the layers are stored as a Collection
, you can always change their rendering order by sorting them or changing their position in the list.
You can always tweak on the minor details from my example to customize what you need.
To add a Layer:
BufferedImage layer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
advancePaint.addLayer(layer);
Using BufferedImage.TYPE_INT_ARGB
, the background will be transparent, hence other layers will be able to "shine through".