这个问题是基于我不久前在一个简单的 Swing 骰子程序中遇到的问题。我发布的原始问题是here https://stackoverflow.com/questions/22306637/mystery-concurrency-component-drawing-bug-in-very-simple-swing-dice-program并有一个公认的答案,但我想确切地知道发生了什么,为什么会出现问题,以及为什么解决方案有效。
我设法削减原始代码以找到问题的核心,现在看起来非常不同:
- 我有两个
ColorPanel
分别画一个彩色方块
- 当您单击面板时,该框应按以下顺序更改颜色:从黑色开始,然后>红色>绿色>蓝色>红色>绿色>蓝色>等
- 一旦盒子改变颜色,它就不会再变成黑色
然而当我刚刚打电话时repaint()
in the MouseListener
,该程序的行为非常奇怪:
- 我单击一个面板,方块的颜色发生变化
- 然后我点击另一个,它的方块颜色改变,但第一个方块也变回黑色
- 你可以在下面的 gif 中看到这种行为:
如果你使用getParent().repaint()
相反,这种行为消失并且程序按预期运行:
- 该问题似乎仅在面板/方块开始“重叠”时才会出现。
- 如果您使用阻止此问题的布局或不将尺寸设置得较小,则问题似乎不会发生。
- 这个问题并不是每次都会发生,这最初让我认为可能涉及并发问题。
- 我在最初的问题中遇到问题的代码似乎并没有给每个人带来问题,因此我的 IDE、jdk 等也可能相关:Windows 7、Eclipse Kepler、jdk1.7.0_03
减去导入等的代码如下:
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();
}
});
}
}
所以我的问题是,这里到底发生了什么?
但我想确切地知道发生了什么
我在 Windows 7 上使用 JDK7u60 时看到了同样的问题。对我来说这绝对是一个错误。
我最好的猜测是这是双缓冲的问题。
我将调试代码添加到paintComponent()
方法。
1)当你点击右边的组件时,只有它的paintComponent()
调用方法并将面板涂上适当的颜色。
2)当您单击左侧组件时,仅其paintComponent()
方法被调用并且面板被涂上正确的颜色,但是右侧的面板恢复为黑色,而不调用paintComonent()
右侧面板上的方法。这让我相信不知何故正在使用旧的缓冲区(这将是错误,我不知道如何修复它)。
原因是getParent().repaint()
之所以有效,是因为无论您单击哪个面板,这都会强制重新绘制两个组件。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)