使用线程时,Swing GUI冻结

时间:2019-05-14 08:01:44

标签: java swing

我正在编写一个突破游戏,除一件小事外,其他一切都正常。

我有一个从线程和RepainterThread扩展的球对象,该对象可以实现Runnable或扩展Thread,后者调用paint方法,该方法使用砖块,球拍和Ball重新渲染游戏领域

我有一个连接所有东西的Singelton GameController。

我有一个带有isActive布尔值的GameState来决定是否应该暂停游戏。

我开始游戏,我可以玩,程序的行为应达到预期。 当球碰到一切都很好时,框架被吸引,球移动砖块破裂。

然后,我通过将“活动”设置为“假”的按钮暂停游戏。 球停了,应该停下来。然后,我点击继续按钮,isActive再次成立。球对象再次开始运行,并且重新触发了Repainter Thread的运行方法,但“摆动框架”完全冻结。

我尝试了各种方法,这些是我最近的方法。

我花了几天时间来帮助

public class Ball extends MovingObject {

    private double hSpeed; // Horizontal velocity
    private double vSpeed; // Vertical velocity

    public Ball() {
        this.color = Color.MAGENTA;
        this.height = GameSettings.ballSize;
        this.width = GameSettings.ballSize;
        this.position = new Point2D.Double(GameSettings.defaultBallX, GameSettings.defaultBallY);
        this.hSpeed = GameSettings.ballHSpeed;
        this.vSpeed = GameSettings.ballYSpeed;
    }

    public Ball(Ball ball) {
        color = ball.color;
        height = ball.height;
        width = ball.width;
        position = ball.position;
        hSpeed = ball.hSpeed;
        vSpeed = ball.vSpeed;
    }

    public double getHSpeed() {
        return this.hSpeed;
    }

    public double getVSpeed() {
        return this.vSpeed;
    }


    public void run() {

        try {
            while (GameController.getInstance().getGameState().isActive()) {
                System.out.println("Ich run im Ball");
                Thread.sleep(10);
                this.meetingWall();
                this.meetingBrick();
                this.position.setLocation(this.getPosition().getX() + this.hSpeed,
                        this.getPosition().getY() + this.vSpeed);
                if (this.meetingPaddle()) {
                    this.newDirection();
                }
                if (this.out()) {
                    GameController.getInstance().stopGame();
                    this.stopThread();
                }

                this.position = this.getPosition();

            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    public void stopThread() {
        GameController.getInstance().getGameState().setActive(false);
    }

    public void startThreadAgain() {
        this.run();
    }

    @Override
    public synchronized void start() {
        this.position.setLocation(GameSettings.defaultBallX, GameSettings.defaultBallY);
        super.start();
    }


    class GamePanel extends JPanel {
        private static final long serialVersionUID = 1L;
        private final Color backgroundColor = Color.BLACK;
        GameState gameState = GameController.getInstance().getGameState();

        public GamePanel() {
            super();

            this.addKeyListener(new KeyListener() {
                // Dieser KeyListener soll auf Inputs der Pfeiltasten nach links
                // <- und rechts -> hoeren und eine entsprechende Bewegung des
                // Schlaegers erwirken, aber nur, wenn das Spiel nicht
                // pausiert/gestoppt ist.
                public void keyPressed(KeyEvent keyEvent) {
                    if (gameState.isActive()) {// gameState.isActive()
                        if (keyEvent.getKeyCode() == KeyEvent.VK_RIGHT) {
                            gameState.getPaddle().setPositionRigth();
                        }

                        if (keyEvent.getKeyCode() == KeyEvent.VK_LEFT) {
                            gameState.getPaddle().setPositionLeft();
                        }
                    }

                }

                public void keyReleased(KeyEvent keyEvent) {
                    // TODO
                }

                public void keyTyped(KeyEvent arg0) {
                }
            });
        }


        public void paint(Graphics g) {
            Graphics2D graphics2D = (Graphics2D) g;
            graphics2D.setColor(this.backgroundColor);
            graphics2D.fillRect(0, 0, this.getWidth(), this.getHeight());

            for (int i = 0; i < gameState.getBricks().length; i++) {
                for (int j = 0; j < gameState.getBricks()[i].length; j++) {
                    if ((gameState.getBricks()[i][j] != null)) {
                        graphics2D.setColor(gameState.getBricks()[i][j].getColor());

                        graphics2D.fillRect(
                                (i * GameSettings.brickWidth) + (i + 1) * (GameSettings.spaceAroundBrick + 1),
                                (j * GameSettings.brickHeight) + (j + 1) * GameSettings.spaceAroundBrick,
                                GameSettings.brickWidth, GameSettings.brickHeight);
                    }
                    scoreLabel.setText(this.gameState.getScore() + "");

                    gameState.getPaddle().draw(graphics2D);
                    gameState.getBall().draw(graphics2D);
                }
            }

        }
    }


// First Approach


    private class RepainterThread implements Runnable {

        public RepainterThread() {
            System.out.println("RepainThreadCOntructor");
        }

        private void updateGUI() {
            System.out.println("before invoke later");

            System.out.println("repaint");
            getGamePanel().requestFocus();
            getGamePanel().repaint();

        }

        @Override
        public void run() {
            System.out.println("Repainter run");
            System.out.println(GameController.getInstance().getGameState().isActive());

            while (GameController.getInstance().getGameState().isActive()) {
                System.out.println("inside while");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                updateGUI();

            }

        }

    }

// Second Approach

        private class RepainterThread implements Runnable {


            public RepainterThread() {
                System.out.println("RepainThreadCOntructor");
            }

            private void updateGUI(){

                SwingUtilities.invokeLater(new Runnable() {         
                    public void run() {
                        System.out.println("repaint");
                        getGamePanel().requestFocus();
                        getGamePanel().repaint();
                    }
                });

            }
            @Override
            public void run() {
                System.out.println("Repainter run");
    System.out.println(GameController.getInstance().getGameState().isActive());

                    while (GameController.getInstance().getGameState().isActive()) {
                        System.out.println("inside while");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }

                        updateGUI();


                    }

            }

        }

框架不再冻结

请帮助

1 个答案:

答案 0 :(得分:1)

这是一个疯狂的猜测,但是由于根据您的描述,程序可以正常工作,直到您暂停并取消暂停它为止,问题可能出在startThreadAgain方法上:

public void startThreadAgain() {
    this.run();
}

您的代码没有显示如何调用此方法,但是在该方法中您只是调用this.run(),即您将run方法作为常规的阻塞方法进行调用,而可能仍在UI线程中。相反,您应该调用start()以启动执行run方法的适当的新线程。

public void startThreadAgain() {
    super.start(); // not this start, otherwise it resets the ball's location
}