虽然循环似乎打破了绘画代码

时间:2013-06-03 00:33:00

标签: java

以下代码示例让我对正在进行的项目感到悲伤:

这是我的问题......

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

            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

完成EXCERPT:

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

2 个答案:

答案 0 :(得分:1)

看起来你试图在Event Dispatching Thread的上下文中执行循环。

除其他事项外,EDT负责处理重绘请求。这意味着如果你做任何阻止这个线程运行的东西,它就不能重新绘制屏幕,​​直到阻止它完成为止。

这可以解释您的部分问题。

请查看Concurrency in 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);
        }    
    }        
}

答案 1 :(得分:1)

您在事件发送线程或简称EDT上呼叫Thread.sleep

EDT是挥杆完成所有工作的地方。如果你让它进入睡眠状态,那么Swing将不会进行任何绘画或处理任何用户输入。

一种解决方案是将while循环的主体放入SwingTimer,每秒运行一次。

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