为什么不重写()总是调用paintComponent以及为什么它在调用时并不总是正常运行

时间:2012-10-07 23:33:11

标签: java repaint paintcomponent repaintmanager

我正在用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());
    }

}

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

        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()方法也是这种情况,我希望它在更新框架后在清除一行并放下它们后显示新位置的块。同样,不调用paintComponent()。 然而,对于最后一次repaint()调用,我只想更新下落片段的位置而不管它之前可能需要或不需要做什么更新,重绘()DOES调用paintComponent()。所以:第一个问题是,为什么paintComponent()只在这个repaint()调用的实例中被调用。

但是,当调用paintComponent()并且它到达方法的末尾时,我在调试模式下跟踪它以查看面板反映更改的行。一旦到达:&#34; Repaintmanager.paintDirtyRegions(Map&lt; Component,Rectangle&gt;)&#34; line:856,它清除了行并显示了新的下降块,但是有隐形块和幻像块。

所以,我的第二个问题是,为什么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);
}

}

如果这是令人讨厌的话,我道歉。

3 个答案:

答案 0 :(得分:1)

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

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

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

来自Java Docs

  

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

     

很少需要调用此方法。在大多数情况下,它更多   高效地调用重绘,这推迟了实际绘画和可以   将冗余请求折叠为单个绘制调用。这个方法是   如果在当前事件发生时需要更新显示,则非常有用   被派遣。

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

答案 1 :(得分:-1)

repaint()请勿致电paintComponent(),这对于repaint()方法来说是正确的工作场景。

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

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

答案 2 :(得分:-3)

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

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

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