gpt4 book ai didi

java - 为什么 repaint() 不会总是调用 PaintComponent 以及为什么它在被调用时并不总是表现正常

转载 作者:行者123 更新时间:2023-12-02 05:00:10 25 4
gpt4 key购买 nike

我正在用 Java 开发俄罗斯方 block 克隆,一切似乎都工作正常,直到我想要清除整行并删除上面的所有内容。尽管我的所有数据都正确地表示了转换,但我的 PaintComponent 方法似乎只清除了该行,但将上面显示的所有内容保留为 repaint() 调用之前的样子。新的棋子将穿过幻影方 block 掉落并落在底行的隐形方 block 上,上面的棋子本来会掉落在那里。

这是我的绘画组件方法:

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());
}

}

这是我的 Timer 监听器中的 actionPerformed 方法的一部分,用于检测/清除 block 并调用重绘方法。

        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() 方法时,井数组正确显示整行现在完全为空。我希望 repaint() 方法更新面板以显示此空行,但似乎没有调用 PaintComponent() 。第二个 repaint() 方法也是如此,我希望它在清除一行并将其放下后更新框架以在新位置显示 block 。同样,paintComponent() 没有被调用。然而,对于最后一次 repaint() 调用,我只想更新下落碎片的位置,无论它之前可能需要或可能不需要进行任何更新,repaint() 确实会调用paintComponent()。所以:第一个问题是,为什么 PaintComponent() 仅在 repaint() 调用的这个实例中被调用。

但是,当调用paintComponent()并且它到达方法的末尾时,我在 Debug模式下跟踪它以查看面板在哪一行反射(reflect)了更改。一旦到达:“Repaintmanager.paintDirtyRegions(Map< Component,Rectangle >)”行:856,它就清除了该行并显示新的下落 block ,但有不可见的 block 和幻像 block 。

所以,我的第二个问题是,为什么 PaintComponent() 会以这种方式运行。显然,我需要大量阅读有关 Repaintmanager 和 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);
}

}

如果这篇文章太长,我深表歉意。

最佳答案

首先,如果您还没有这样做,我会通读一下 Painting in AWT and Swing ,它解释了 Swing(和 AWT)使用的绘制方案。

其次,您无法控制重绘,重绘管理器和操作系统可以控制,您只需提供建议。

第三,你可以看看JComponent.paintImmediately方法,它需要知道您要更新的区域,但可能会有所帮助

来自 Java 文档

Paints the specified region in this component and all of its descendants that overlap the region, immediately.

It's rarely necessary to call this method. In most cases it's more efficient to call repaint, which defers the actual painting and can collapse redundant requests into a single paint call. This method is useful if one needs to update the display while the current event is being dispatched.

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

关于java - 为什么 repaint() 不会总是调用 PaintComponent 以及为什么它在被调用时并不总是表现正常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12773749/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com