views:

175

answers:

3

Hello,

I have a window that has two layers: a static background and a foreground that contains moving objects. My idea is to draw the background just once (because it's not going to change), so I make the changing panel transparent and add it on top of the static background. Here is the code for this:

public static void main(String[] args) {
    JPanel changingPanel = new JPanel() {

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.RED);
            g.fillRect(100, 100, 100, 100);
        }
    };
    changingPanel.setOpaque(false);

    JPanel staticPanel = new JPanel();
    staticPanel.setBackground(Color.BLUE);
    staticPanel.setLayout(new BorderLayout());
    staticPanel.add(changingPanel);

    JFrame frame = new JFrame();
    frame.add(staticPanel);
    frame.setSize(800, 600);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
}

This piece of code gives me the correct image I want, but every time I repaint changingPanel, staticPanel gets repainted as well (which is obviously against the whole idea of painting the static panel just once). Can somebody show me what's wrong?

FYI I am using the javax.swing.Timer to recalculate and repaint the changing panel 24 times every second.

+2  A: 

This is exactly the way painting works. Swing has to search for the first component that has a non-opaque background. Then it paints that component and the children to make sure all the painting is done correctly.

Even if you have a moving compnent, SWing would still need to "clear" the last position of the compnent, which means it has to at least repaint that area of the background panel, before repaint the component that moved.

To make the painting more efficient the child panel should be opaque. I don't know why you changed the default setting.

camickr
He probably set opaque to false because he wants to paint non-rectangular shapes on the component later...
Nate
+4  A: 

When you repaint a transparent component above another, you still 'dirty' the lower component, causing it the be repainted. If you didn't repaint the lower layer, you would get a smearing effect of the image on top of it.

The only optimisation available here is not regenerating the image used on the lower level. The raster still needs to be painted to the graphics buffer every time the layer above changes.

Cogsy
yes I agree, so no go for me
phunehehe
+2  A: 

A really easy way is to use jxlayer. Implement AbstractLayerUI and add that over your component. See here to get started.

Chuk Lee
thanks for telling me about jxlayer, but as I tried the lower layer is still repainted every time :(
phunehehe
There is nothing much you can do. The JPanel.paintComponent() gets called eveytime you resize the frame, or scroll it as in a JScrollPane. You can minimize the time spend in paintComponent() by having a backbuffer. In your paintComponents() only paint the backbufer and nothing else.
Chuk Lee