java - 为什么在使用 repaint() 而不是 getParent().repaint() 时会出现此 Swing 错误?

标签 java swing drawing paintcomponent repaint

这个问题是基于我不久前遇到的一个简单的 Swing 骰子程序问题。我发布的原始问题是 here并且有一个可接受的答案,但我想确切地知道发生了什么,为什么会出现问题,以及解决方案为什么有效。

我设法削减了原始代码以找到问题的核心,现在它看起来非常不同:

  • 我有两个 ColorPanel,每个绘制一个彩色方 block
  • 当你点击一个面板时,盒子应该按以下顺序改变颜色:从黑色开始,然后>红色>绿色>蓝色>红色>绿色>蓝色>等等
  • 一旦盒子改变了颜色,它就永远不会再变黑

然而,当我在 MouseListener 中调用 repaint() 时,程序的行为非常奇怪:

  • 我点击一个面板,正方形的颜色发生变化
  • 然后我点击另一个,它的方 block 变了颜色,但第一个方 block 也变了,变回黑色
  • 您可以在下面的 gif 中看到此行为:

buggy program

如果您改用 getParent().repaint(),此行为就会消失并且程序会按预期运行:

enter image description here

  • 问题似乎只有在面板/正方形开始“重叠”时才会出现。
  • 如果您使用的布局可以阻止这种情况发生,或者没有将尺寸设置得较小,那么问​​题似乎就不会发生。
  • 问题并不是每次都发生,这让我最初认为可能涉及并发问题。
  • 我在最初的问题中遇到问题的代码似乎并没有给每个人带来问题,所以我的 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();
            }

        });
    }
}

所以我的问题是,这里到底发生了什么?

最佳答案

but I'd like to know exactly what is happening,

我在 Windows 7 上使用 JDK7u60 时发现了同样的问题。对我来说这绝对是一个错误。

我最好的猜测是双缓冲有问题。

我在 paintComponent() 方法中添加了调试代码。

1) 当您点击正确的组件时,只有它的 paintComponent() 方法被调用并且面板被涂上正确的颜色。

2) 当你点击左边的组件时,只有它的 paintComponent() 方法被调用并且面板被涂上正确的颜色,但是右边的面板恢复为黑色,没有在右侧面板上调用 paintComonent() 方法。这使我相信以某种方式使用了旧缓冲区(这将是错误,我不知道如何修复它)。

getParent().repaint() 起作用的原因是无论您单击哪个面板,这都会强制重新绘制两个组件。

关于java - 为什么在使用 repaint() 而不是 getParent().repaint() 时会出现此 Swing 错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24222976/

相关文章:

java - xmx和MaxRAM JVM参数之间有什么区别?

java - AndEngine - 滚动 map 时的 Artifact (TextureOptions 相关)

java - Swing JScrollPane 更新时重置滚动位置

java - GUI 测试应该以默认外观运行吗?

android - 如何通过手指拖动在 Canvas 上绘制图案

java - Wildfly - 失败登录异常 : Password Incorrect/Password Required Exception

java - 为什么每个幸存者空间和伊甸园之间的比例与 SurvivorRatio 不匹配?

java - 设置单独行高时 JTable 内存泄漏

c# - System.Drawing 的撤消按钮?

.net - 使用 Winform 绘图