-1

以下代码示例在我正在做的一个项目中让我有些悲伤:

这是我的问题...

此代码导致在窗口上绘制一个正方形网格,以及一个彩色形状,从该网格的顶部开始:

            MainWindow mainAppWindow = mainAppWindow = new MainWindow("TETRIS");
            mainAppWindow.setExtendedState(Frame.MAXIMIZED_BOTH);
            mainAppWindow.setVisible(true);

            TetriminoFactory blockBuilder = mainAppWindow.getGameBoard().getBlockFactory();
            mainAppWindow.getGameBoard().setActiveTetrimino(blockBuilder.createTetrimino());
            Tetrimino activeTetrimino = mainAppWindow.getGameBoard().getActiveTetrimino();

在此之后,我有一个 while 循环,它应该每秒将形状向下移动指定距离。这个动作应该在窗口上表现出来:

while((activeTetrimino.getLowermostPiece().getLoc().getYPos() / MiscConsts.TETRIS_UNIT) <= mainAppWindow.getGameBoard().getLowermostRowIndex())
        {
            if(activeTetrimino.checkForNeighbouringBlock().equals(Collision.BLOCK_BELOW_ME))
            {
                if(!activeTetrimino.setSecuredState(true))
                {
                    activeTetrimino = blockBuilder.createTetrimino();
                }
            }
                activeTetrimino.moveTetrimino(0, MiscConsts.TETRIS_UNIT);
                mainAppWindow.canvas.repaint();

            try {
        Thread.sleep(MiscConsts.TIME_BETWEEN_ADVANCEMENTS);
                } catch (InterruptedException e) {
                System.out.println("ERROR - InterruptedException thrown in operate(). Terminating.");
                e.printStackTrace();
                System.exit(1000);
            }
        }

正是在这一点上,我遇到了一个问题。该循环似乎撤消了所有先前的绘图,并产生了一个空白屏幕。如果我将循环注释掉,则会绘制网格以及形状,但当然不会发生任何移动。我不确定这里发生了什么,但我有预感它与线程或其他东西有关。或者也许只是 while 循环是反摇摆:P

完整摘录:

public static void main(String[] args)
        {
            theApp = new Tetris();

        SwingUtilities.invokeLater(new Runnable() 
                                        {
                                            public void run()
                                            {
                                                theApp.createGUI();     // Call GUI creator
                                            }
                                        });
    }

    public void createGUI()
    {
        MainWindow mainAppWindow = mainAppWindow = new MainWindow("TETRIS");
        mainAppWindow.setExtendedState(Frame.MAXIMIZED_BOTH);
        mainAppWindow.setVisible(true);

        TetriminoFactory blockBuilder = mainAppWindow.getGameBoard().getBlockFactory();
        // NEEDS WORK???
        mainAppWindow.getGameBoard().setActiveTetrimino(blockBuilder.createTetrimino());

        Tetrimino activeTetrimino = mainAppWindow.getGameBoard().getActiveTetrimino();


        while((activeTetrimino.getLowermostPiece().getLoc().getYPos() / MiscConsts.TETRIS_UNIT) <= mainAppWindow.getGameBoard().getLowermostRowIndex())
    {
        if(activeTetrimino.checkForNeighbouringBlock().equals(Collision.BLOCK_BELOW_ME))
        {
            if(!activeTetrimino.setSecuredState(true))
            {
                activeTetrimino = blockBuilder.createTetrimino();
            }
        }
            activeTetrimino.moveTetrimino(0, MiscConsts.TETRIS_UNIT);
            mainAppWindow.canvas.repaint();

        try {
    Thread.sleep(MiscConsts.TIME_BETWEEN_ADVANCEMENTS);
            } catch (InterruptedException e) {
            System.out.println("ERROR - InterruptedException thrown in operate(). Terminating.");
            e.printStackTrace();
            System.exit(1000);
        }
    }
    }
4

2 回答 2

1

看起来您正试图在事件调度线程的上下文中执行循环。

除其他外,EDT 负责处理重绘请求。这意味着如果您执行任何阻止此线程运行的操作,它无法重新绘制屏幕,​​直到曾经阻止它的内容完成。

这将解释您的部分问题。

查看Swing 中的并发以获取更多详细信息。

可能最简单的解决方案是将您的while外观javax.swing.Timer替换为

例如...

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestBrick {

    public static void main(String[] args) {
        new TestBrick();
    }

    public TestBrick() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private int yPos = 0;

        public TestPane() {
            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    yPos++;
                    if (yPos + 10 > getHeight()) {
                        yPos = 0;
                    }
                    repaint();
                }
            });
            timer.setRepeats(true);
            timer.setCoalesce(true);
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g); 
            int width = getWidth();
            int xPos = (width - 10) / 2;
            g.drawRect(xPos, yPos, 10, 10);
        }    
    }        
}
于 2013-06-03T00:37:43.990 回答
1

您正在调用Thread.sleep事件调度线程或简称 EDT。

EDT 是 swing 完成所有工作的地方。如果您将其置于睡眠状态,则 Swing 将不会进行任何绘画或处理任何用户输入。

一种解决方案是获取 while 循环的主体并将其放入每秒运行的SwingTimer中。

另一个更复杂的解决方案是使用 awt 画布,它有自己的绘制上下文,可以在不同的线程中绘制并在该线程中运行循环。如果您想采用画布方法,请查看Gamedev关于Java 中的 Active Rendering的文章。

于 2013-06-03T00:38:23.393 回答