I know Swing very poorly, so sorry for stupid question.
What I need to do is to make my custom components (they are ancestors of JPanel
) with painting performed from the buffer (BufferedImage
instance). It is a requirement, because the painting procedure might be very heavy, so paintComponent method is overridden to draw from that buffer and return imediately (but if you know better ways to tell Java not to repaint the object over 200-300 times a second consuming all the CPU - I would appreciate, maybe there are some public methods to mark regions of Graphics context as "not changed", so Swing does not try to repaint them).
What is wrong with my code that it simply does not draw data on overlapping JPanels. I have made a reproducable example of the core of the problem. See the code below:
public class Dr extends JPanel {
public Dr(int x, int y, int w, int h, int fw, int fh) {
left = x;
top = y;
width = w;
height = h;
full_width = fw;
full_height = fh;
setOpaque(true);
}
public void draw() {
if (buffer == null && width > 0 && height > 0) {
buffer = new BufferedImage(width, height, java.awt.image.BufferedImage.TYPE_INT_ARGB);
}
if (buffer == null) return;
Graphics g = buffer.getGraphics();
setBounds(0, 0, full_width, full_height);
Graphics2D g2d = (Graphics2D)g;
g2d.setBackground(Color.WHITE);
g2d.clearRect(0, 0, full_width, full_height);
g2d.setColor(new Color(255, 0, 80, 128));
g2d.fillRect(left, top, width, height);
System.out.println(left + ", " + top);
}
@Override
public void repaint() {
draw();
}
@Override
public void paintComponent(Graphics g) {
g.drawImage(buffer, 0, 0, null);
}
private BufferedImage buffer;
private int left;
private int top;
private int width;
private int height;
private int full_width;
private int full_height;
}
This is a sample class that does nothing but saving his coordinates to draw at and full dimensions (which I want to be equal to its parent dimensions, that's a requirement again because I need to support visible overflowing content to be able to be displayed) and drawing a red rectangle with half of the 100% opacity.
Here is the outer code that uses it:
Dr dr1 = new Dr(4, 4, width-10, 80, width-2, height-2);
Dr dr2 = new Dr(4, 88, width-10, 80, width-2, height-2);
root.add(dr1);
root.add(dr2);
dr1.setBounds(0, 0, width-2, height-2);
dr2.setBounds(0, 0, width-2, height-2);
dr1.draw();
dr2.draw();
What is expected to be:
What is displayed when I remove my buffer and draw in paintComponent
method directly:
What is displayed when I don't fill the background (here the background has system L&F color, but I need the color of element's parent (in my example it is white)
What is displayed when I drraw from my buffer
The last one is completely amuzing. The red rectangle is partly cut off from the right and from the bottom, and the full image (including the white background) is clipped from the (0, 0) coordinate of the parent panel. The second object is not displayed at all. The coordinates in the console are absolutely OK.
I feel there is something I have to do with Swing to tell it not to perform its "magic" upon guessing what to paint and what not to paint. But how can I do that?
UPDATE:
I found that even if I don't call draw()
method of my child components after I added them, they still hide their parent's background (which should not happen, bacase JPanels are meant to be opaque). So the core problem is that I can't make my Dr
objects have opaque background (e.g. no background) where nothing is painted in them (it also explains why I see only the first rectangle - the z-order in Swing seems to be reversed, e.g. the last added component is painted at the bottom, as it was the farthest from us).