当前位置: 首页 > 知识库问答 >
问题:

为什么不reaint()总是调用油漆组件,为什么它在被调用时不总是表现正常

东门越
2023-03-14

我正在用Java开发一个俄罗斯方块克隆,在我想要清除整行并删除上面的所有内容之前,一切似乎都正常工作。虽然我所有的数据都正确地表示了转换,但我的paintComponent方法似乎只清除了行,但上面显示的所有内容都保持在repaint()调用之前的状态。新的碎片将穿过幻影积木,落在最下面一排的隐形积木上,上面的碎片会落在那里。

这是我的油漆成分方法:

public void paintComponent(Graphics page)
{
    super.paintComponent(page);
    Graphics2D page2D = (Graphics2D) page;
    for (int c = 0; c < 10; c++) 
    {
        for (int r = 0; r < 18; r++)
        {
            if (well[c][r] != null) //Well is a 2D array of Block objects that have Rectangle object, coordinates and color
            {
                page2D.setColor(well[c][r].getColor());
                page2D.fill(well[c][r].getSquare());
                page2D.setColor(Color.gray);
                page2D.draw(well[c][r].getSquare());
            }       

        }
    }
    for (int i = 0; i < 4; i++) //tetro = the player's tetris piece
    {
        page2D.setColor(tetro.getColor());
        page2D.fill(tetro.getBlock(i).getSquare());
        page2D.setColor(Color.GRAY);
        page2D.draw(tetro.getBlock(i).getSquare());
    }

}

这是计时器侦听器中actionPerformed方法的一部分,用于检测/清除块并调用repaint方法。

        int count = 0;  //Number of occupied cells in well
        int clears = 0; //number of rows to be clear
        int lowestClear = -1; //Lowest row that was cleared, -1 if none
        for (int row = 0; row < 18; row++)
        {
            for (int col = 0; col < 10; col++)
            {
                if (well[col][row] != null)
                {
                    count++;
                }
            }
            if (count == 10)
            {
                clears++;
                if (lowestClear < 0)
                {
                    lowestClear = row;
                }
                for (int col = 0; col < 10; col++)
                {
                    well[col][row] = null;
                }
            }
            count = 0;
        }
        if (clears > 0)
        {
            repaint(); //Doesn't call paintComponent()
            for (int i = 1; i <= clears; i++)
            {
                for (int r = 16; r >= 0; r--)
                {
                    if (r > lowestClear)
                    {
                        break;
                    }
                    for (int c = 0; c < 10; c++)
                    {
                        if (well[c][r] != null)
                        {
                            well[c][r+1] = well[c][r];
                            well[c][r] = null;
                        }           
                    }
                }
            }
            repaint(); //Does not call paintComponent()
        }       
        tetro.fall();
        repaint(); //DOES call paint component

在调用第一个repaint()方法时,well数组正确地显示整行现在完全为空。我希望repaint()方法更新面板以显示这一空行,但似乎没有调用paintComponent()。第二个repaint()方法也是如此,我希望它在清除一行并将其放下后,更新帧,以在新位置显示块。同样,paintComponent()没有被调用。然而,对于最后一个repaint()调用,我只想更新下落部件的位置,而不管它之前是否需要进行任何更新,repaint()确实调用了paintComponent()。所以:第一个问题是,为什么paintComponent()只在repaint()调用的这个实例中被调用。

然而,当调用paintComponent()并到达方法的末尾时,我会在调试模式下跟踪它,以查看面板在哪一行反映更改。一旦到达:“RepaitManager.PaintDirtRegions(地图

所以,我的第二个问题是,为什么paintComponent()会以这种方式运行。显然,我需要好好阅读一下RepaitManager和Java绘画,但如果有人能给我解释一下,我将不胜感激。

以下是重要的主要方法:

import javax.swing.JFrame;

public class TetrisDriver 
{


public static void main(String[] args) 
{
    JFrame frame = new JFrame("Tetris");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    frame.getContentPane().add(new Matrix()); //Matrix = jPanel class
    frame.pack();
    frame.setVisible(true);
}

}

如果时间过长,我道歉。

共有3个答案

濮阳耀
2023-03-14

您可以尝试自己直接调用paint(),而不是使用repaint()

Graphics g;
g = getGraphics();
paint(g);

这样,当您想进行更改时,它将立即绘制。将此分配给另一个函数,并在您想立即看到更改时调用它。

岳风畔
2023-03-14

repaint()不要调用paintComponent(),这就是repaint()方法的正确工作场景。

它只标记组件应该重新绘制的状态,Swing本身会进一步调用paintComponent()。

许多repaint()调用只能导致单个paintComponent()调用,这是有效的行为。

郦祯
2023-03-14

首先,如果你还没有这样做,我会通读AWT和Swing中的绘画,这解释了Swing(和AWT)使用的绘画方案。

其次,你不控制重绘,重绘管理器和操作系统控制重绘,你只是提供建议。

第三,你可以看看JComponent.paint立即方法,它需要知道你想要更新的领域,但可能会有所帮助

来自Java文档

立即绘制此组件中的指定区域及其与该区域重叠的所有子体。

很少有必要调用此方法。在大多数情况下,调用重新绘制更有效,它会推迟实际的绘制,并将冗余请求折叠成单个绘制调用。如果需要在分派当前事件时更新显示,此方法非常有用。

我可能会更谨慎地将游戏状态渲染到屏幕外缓冲区,并在paintComponent方法中使用它。你可以把它们放在一个队列中,然后在绘制过程中弹出它们,这样就可以根据需要创建更多或更少的内容(保留一些内容,并不断增长,根据需要缩小这些内容)。。。

 类似资料:
  • 问题内容: 我读过,我们应该始终在循环内调用a : 它可以正常工作而没有循环,那为什么呢? 问题答案: 你不仅需要循环它,还需要在循环中检查条件。Java不能保证仅通过notify()/ notifyAll()调用或正确的notify()/ notifyAll()调用来唤醒你的线程。由于此属性,无环版本可能在你的开发环境上工作,而在生产环境上意外失败。 例如,你正在等待一些东西: 邪恶的线程出现了

  • 问题内容: 我只是想简化我的一个类,并以与flyweight设计模式相同的样式介绍了一些功能。 但是,对于为什么总是调用after ,我有点困惑。我没想到这一点。谁能告诉我为什么会这样,否则我如何实现此功能?(除了将实现放入hack之外)。 这是一个例子: 输出: 为什么? 问题答案: 使用 时,你需要控制一个新实例的创建。 使用 时,你需要一个新的实例的控件初始化。 是实例创建的第一步。首先调用

  • 本文向大家介绍为什么在__new __()之后总是调用__init __()?,包括了为什么在__new __()之后总是调用__init __()?的使用技巧和注意事项,需要的朋友参考一下 Python具有一种称为魔术方法的特殊类型的方法,该方法以前置和双下划线命名。 如果我们想谈论魔术方法__new__,那么显然也需要谈论__init__方法。创建实例时将调用魔术方法__new__。而在创建实

  • 只是一个关于继承的理论问题。 假设我有一个类“GamePanel”,它扩展了JPanel。 我知道在课堂上,如果我调用,它将调用父类(JPanel)绘制方法。 但是如果我创建一个对象GamePanel,它不应该继承所有的JPanels方法吗?那么在这种情况下,为什么不工作?当前对象应该能够访问该方法,对吗? 如果没有,为什么

  • 问题内容: 我只是想简化我的一个类,并以与flyweight设计模式相同的样式介绍了一些功能。 但是,对于为什么总是被称为after ,我有点困惑。我没想到这一点。谁能告诉我为什么会这样,否则我如何实现此功能?(除了将实现放到中之外)。 这是一个例子: 输出: 为什么? 问题答案: 使用时,你需要控制一个新实例的创建。 使用 时,你需要一个新的实例的控件初始化。 是实例创建的第一步。首先调用它,它

  • 我在活动的中放置了一些缓存清理代码,但大多数情况下,除非通过显式地完成活动,否则这些代码不会执行。 编辑:只读仅在或系统资源不足时调用。那么我需要把我的缓存清理代码放在哪里呢?如果我把它放在中,用户返回到应用程序,缓存就会被清除。我实际上是在缓存中存储重要的临时文件,这些文件不应该在中删除。