tags:

views:

70

answers:

2

Hi guys, please see the following code:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Main {
    public static void main(String[] args) {
    final JFrame f=new JFrame("foo");
    final JPanel c=new JPanel(null);
    f.setContentPane(c);
    c.setPreferredSize(new Dimension(500,500));
    final JPanel a=new JPanel(null){
        @Override
        protected void paintComponent(Graphics g) {
        g.setColor(Color.red);
        g.fillRect(0, 0, getWidth(), getHeight());
        }
    };
    a.setBounds(0,0,300,300);
    c.add(a);
    final JPanel b=new JPanel(null){
        @Override
        protected void paintComponent(Graphics g) {
        g.setColor(Color.green);
        g.fillRect(0, 0, getWidth(), getHeight());
        }
    };
    b.setBounds(200,200,500,500);
    c.add(b);
    c.setComponentZOrder(a, 0);
    f.pack();
    f.setVisible(true);
    f.addMouseListener(new MouseAdapter() {

        @Override
        public void mouseClicked(MouseEvent e) {
        b.repaint();
        }
    });
    }
}

It basically just draws two panels on top of third one: panel A, which is red, and panel B, which is green. The red panel A has lower z-order and is therefore painted over the panel B. Now if we force the panel B to repaint itself (just click on the JFrame, outside of both panels A and B), suddenly the panel B paints OVER the panel A.

If I switch to using JComponent instead of JPanel, it works correctly and B will not paint over A. It would seem that JPanel simply ignores the Z-order. So, the solution seems to be to use JComponent instead of JPanel. Just out of curiosity - is this Z-order-ignoring behavior normal for JPanel?

+1  A: 

Try c.repaint() in your mouse handler. Also, you don't need to override paintComponent() to change the background color.

public static void main(String[] args) {
    final JFrame f = new JFrame("foo");
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    final JPanel c = new JPanel(null);
    f.setContentPane(c);
    c.setPreferredSize(new Dimension(500, 500));
    final JPanel a = new JPanel();
    a.setBounds(0, 0, 300, 300);
    a.setBackground(Color.red);
    c.add(a);
    final JPanel b = new JPanel();
    b.setBounds(200, 200, 300, 300);
    b.setBackground(Color.green);
    c.add(b);
    c.setComponentZOrder(a, 0);
    f.pack();
    f.setVisible(true);
    f.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {
            c.repaint();
        }
    });
}
trashgod
+3  A: 

If I switch to using JComponent instead of JPanel, it works correctly and B will not paint over A.

Your code is telling the red panel to repaint itself so it does. Now try changing the size of the JFrame and the panels will repaint. This is because the Z-Order only applies when the parent panel repaints all its children. That is why trashgod's solution works.

The reason the JComponent behaves the way it does is because it is non-qpaque, so whenever it needs to be repainted the background of its parent needs to be painted first so you end up invoking the painting in the Z-Order of the parent panel.

So the difference between the two is the opaqueness of the components.

camickr
Excellent; more discussion may be found in "Additional Paint Properties": http://java.sun.com/products/jfc/tsc/articles/painting/#props
trashgod