This question is based on a problem I had a while back with a simple Swing dice program. The original question I posted is here and has an accepted answer, but I'd like to know exactly what is happening, why the problem occurs, and why the solution works.
I managed to whittle down the original code to get to the core of the problem and it now looks very different:
- I have two
ColorPanel
s that each draw a coloured square - when you click on a panel the box should change colour in this order: start at black, then >red>green>blue>red>green>blue> etc
- once a box has changed colour it should never be black again
However when I just call repaint()
in the MouseListener
, the program behaves very strangely:
- I click on one panel and the square's colour changes
- I then click on the other and it's square changes colour, but the first square also changes, back to black
- you can see this behaviour in the gif below:
If you use getParent().repaint()
instead this behaviour goes away and the program behaves as expected:
- The problem only seems to occur if the panels/squares start off 'overlapping'.
- If you use a layout that stops this or don't set the size small then the problem does not seem to occur.
- the problem doesn't happen every time which initially made me think that concurrency problems might be involved.
- The code that I had problems with in my original question did not seem to cause problems for everybody and so my IDE, jdk etc might be relevant as well: Windows 7, Eclipse Kepler, jdk1.7.0_03
The code minus imports etc is as follows:
public class ColorPanelsWindow extends JFrame{
static class ColorPanel extends JPanel {
//color starts off black
//once it is changed should never be
//black again
private Color color = Color.BLACK;
ColorPanel(){
//add listener
addMouseListener(new MouseAdapter(){
@Override
public void mousePressed(MouseEvent arg0) {
color = rotateColor();
repaint();
//using getParent().repaint() instead of repaint() solves the problem
//getParent().repaint();
}
});
}
//rotates the color black/blue > red > green > blue
private Color rotateColor(){
if (color==Color.BLACK || color == Color.BLUE)
return Color.RED;
if (color==Color.RED)
return Color.GREEN;
else return Color.BLUE;
}
@Override
public void paintComponent(Graphics g){
g.setColor(color);
g.fillRect(0, 0, 100, 100);
}
}
ColorPanelsWindow(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new GridLayout(1,0));
add(new ColorPanel());
add(new ColorPanel());
//the size must be set so that the window is too small
// and the two ColorPanels are overlapping
setSize(40, 40);
// setSize(300, 200);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run() {
new ColorPanelsWindow();
}
});
}
}
So my question is, what on earth is going on here?