java.util.Timer&&;秋千事故

java.util.Timer&&;秋千事故,java,multithreading,swing,timer,windowlistener,Java,Multithreading,Swing,Timer,Windowlistener,目前,我正在制作一个基于回合的游戏,它有一个剩余时间的JLabel,几个其他的问题/答案/团队分数标签,以及一个带有游戏板的主面板 这段代码的第一个问题是:GameTimer类被调用太频繁,也就是说,它不是每秒被调用一次,而是每秒被调用5-10次。(输出“Timer:+timeappeased”的print语句打印每个数字,最多80个(计时器:1、计时器:2等)大约10秒钟内。作为旁注,问题的时间永远不会超过15秒。while循环不应该在失控之前停止吗?这个问题只会偶尔发生。我假设这是一个与ut

目前,我正在制作一个基于回合的游戏,它有一个剩余时间的JLabel,几个其他的问题/答案/团队分数标签,以及一个带有游戏板的主面板

这段代码的第一个问题是:GameTimer类被调用太频繁,也就是说,它不是每秒被调用一次,而是每秒被调用5-10次。(输出“Timer:+timeappeased”的print语句打印每个数字,最多80个(计时器:1、计时器:2等)大约10秒钟内。作为旁注,问题的时间永远不会超过15秒。while循环不应该在失控之前停止吗?这个问题只会偶尔发生。我假设这是一个与util.Timer相关的错误,不在我的代码中,但我对类的内部工作不太熟悉

第二个问题:for:each循环在一个无限循环中被调用,因为它会打印“到达的问题数:”+Questions.size(),并无限期地继续for:each循环。我不认为windowOpened()可以被调用多次,我还使用windowActivated()获得相同的结果

最后一个问题:时间标签仅在TimePassed超过question.getTime后更新,这意味着标签中只有一个负数。while循环应该检测到TimePassed更大,并停止,但它不会

我被这些弄糊涂了,非常感谢你的帮助

该项目的一点历史:在实现windowListener之前,该类在执行for:each循环之前只等待了30秒,该循环不起作用,因为该窗口将是一个灰色屏幕(未加载)直到计时器完成,然后它将正常加载,但GameTimer在30秒计时器之后立即启动。然后我尝试每秒使用线程更新自己,但这与之前的尝试有类似的问题

除此之外还有其他类别。我认为这两个类别中存在错误:

游戏屏幕代码:

import java.awt.*;
import javax.swing.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import java.util.*;
import java.awt.event.*;

@SuppressWarnings("deprecation")
public class GameScreen implements WindowListener{
    private int team1Score = 0;
    private int team2Score = 0;
    private ArrayList<Question> questions;

    private Question cQuestion;

    private boolean start = false;

    private boolean timesUp = false;
    private boolean isCorrect = false;
    private java.util.Timer timer = new java.util.Timer();
    private int timeElapsed = 0;

    private boolean isTeam1 = true;

    private String correctAnswer = "";
    private String inputAnswer = "";
    private int numIncorrect = 0;

    private TopPanel topPanel = new TopPanel();

    public GameScreen(ArrayList<Question> questions) {
        JFrame gameFrame = new JFrame("Cavazos Math Game");

        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        int width = (int)screenSize.getWidth();
        int height = (int)screenSize.getHeight();

        gameFrame.setSize(width, height);
        gameFrame.setResizable(false);
        gameFrame.setLocationRelativeTo(null);
        gameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        topPanel.setSize(width, 200);

        this.questions = questions;

        BorderLayout layout = new BorderLayout();

        gameFrame.setLayout(layout);

        System.out.println("Reached Image Loading");

        try {
            BufferedImage fieldImage = ImageIO.read(new File("field2.png"));
            GamePanel gamePanel = new GamePanel(fieldImage);
            gamePanel.setSize(width, height - 200);
            gameFrame.add(gamePanel, BorderLayout.CENTER);
        }
        catch(Exception e) {System.out.println("RUH ROH");}

        System.out.println("Reached Layout Loading");

        gameFrame.add(topPanel, BorderLayout.NORTH);
        gameFrame.setVisible(true);

        gameFrame.addKeyListener(topPanel);

        gameFrame.addWindowListener(this);
    }

    public void windowDeactivated(WindowEvent e) {}

    public void windowIconified(WindowEvent e) {}

    public void windowDeiconified(WindowEvent e) {}

    public void windowClosed(WindowEvent e) {}

    public void windowClosing(WindowEvent e) {}

    public void windowActivated(WindowEvent e) {}

    public void windowOpened(WindowEvent e) {
        System.out.println("Reached Questions. Number of question: " + questions.size());

        for(Question question : questions) {
            timeElapsed = 0;
            cQuestion = question;
            timesUp = false;
            topPanel.setQuestion(question.getQuestionString());
            setTimer(question.getTime());
            correctAnswer = question.getAnswer();
            System.out.println(question.getTime() + "");
            while((timeElapsed < question.getTime()) && !isCorrect && (numIncorrect <= 4)) {
                if(!topPanel.getInput().equals("nothing")) { //has an answer been submitted?
                    inputAnswer = topPanel.getInput();
                    if(!inputAnswer.equals(correctAnswer)) { //is it the wrong answer
                        numIncorrect++;
                        topPanel.setAnswer("");
                    }
                    else {
                        numIncorrect = 0;
                        isCorrect = true;
                        if(isTeam1) {
                            team1Score += question.getPoints();
                        }
                        else {
                            team2Score += question.getPoints();
                        }
                    }
                }
                else {

                }
                topPanel.setTimer(cQuestion.getTime() - timeElapsed);
            }
            isTeam1 = !isTeam1;
        }
    }

    class GameTimer extends TimerTask {
        public void run() {
            System.out.println("Timer: " + timeElapsed);
            timeElapsed++;
            topPanel.setTimer(cQuestion.getTime() - timeElapsed);
        }
    }

    public void setTimer(int seconds) {
        System.out.println("Timer has started");
        timer = new java.util.Timer();
        timer.schedule(new GameTimer(), 0, 1000);
    }
}

在while循环的每次迭代中,你都会启动一个新的Timer对象,因此每次在循环中创建一个新的Timer实例时,都会以额外的速度推进timeappead字段。解决方法是不这样做,只使用一个定时器,或者在创建一个新的定时器之前停止一个定时器,…。但是,说了这一点,你还有另一个意义您的代码中存在许多问题,包括:

  • 这是一个Swing应用程序,您不应该使用java.util.Timers,而应该使用javax.Swing.Timers或“Swing Timers”。原因是Swing Timer可以很好地与Swing事件线程配合使用,而实用程序计时器则不能,这可能会导致出现间歇性的、极难调试的错误
  • 您不应该像这样使用while循环,因为这可能会阻塞Swing事件线程(或“事件调度线程”的EDT),导致GUI冻结。相反,请使用计时器和状态机设计来防止需要while循环

如果您需要更详细的帮助,请回复上面的评论,并帮助我们,我们可以自己运行和修改。我们不希望看到您的整个程序,也不希望看到链接,而是显示您的问题的最小程序。

您的代码甚至不应该有while循环——这就是计时器的用途,这就是w计时器替换的帽子。为什么不使用?我只是想说@PM77-1上面说的话(我不能投票支持他的评论,因为我没有票了)--Swing GUI应该使用javax.Swing.Timer或Swing Timer,而不是java.util.Timer。否则,您将遇到一堆线程问题。此外,如果您创建并发布一个没有外部依赖项的文件,将代码压缩到最小的位,并且仍然编译和运行,您将得到更好的答案(例如需要链接到数据库或图像),没有与您的问题无关的额外代码,但仍然演示了您的问题。我们不希望看到您的整个程序,当然也不希望您发布代码链接,但是一个显示问题的可运行的小程序将非常有帮助。此外,代码不应该有
@SuppressWarnings(“弃用”)
。相反,请避免使用不推荐使用的代码。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class TopPanel extends JPanel implements KeyListener {
    JLabel questionLabel = new JLabel("Test Question");
    JTextField answerLabel = new JTextField("Answer label");
    JTextField timer = new JTextField("Timer Label");
    JTextField team1 = new JTextField("Team 1: 0");
    JTextField team2 = new JTextField("Team 2: 0");

    JPanel teamScores = new JPanel();

    //timer.setEditable(false);
    //team1.setEditable(false);
    //team2.setEditable(false);
    //answerLabel.setEditable(false);

    String inputString = "";
    boolean doneInputting = false;

    GridLayout scoresLayout = new GridLayout(2,1);
    GridLayout topLayout = new GridLayout(1,4);

    public TopPanel() {
        teamScores.setLayout(scoresLayout);
        teamScores.add(team1);
        teamScores.add(team2);
        this.setLayout(topLayout);
        this.setSize(getWidth(), 100);
        this.add(questionLabel);
        this.add(answerLabel);
        this.add(timer);
        this.add(teamScores);

        Font topFont = new Font("Sans Serif", Font.PLAIN, 32);

        this.setFont(topFont);
    }

    public void setQuestion(String question) {
        questionLabel.setText(question);
    }

    public void setAnswer(String answer) {
        answerLabel.setText(answer);
    }

    public void setTimer(int time) {
        timer.setText(time + "");
    }

    public void setTeam1Score(int score) {
        team1.setText(score + "");
    }

    public void addTeam1Score(int score) {
        team1.setText(score + "");
    }

    public void setTeam2Score(int score) {
        team2.setText(score + "");
    }

    public String getInput() {
        if(doneInputting) {
            return inputString;
        }
        return "nothing";
    }

    public String getCurrentInput() {
        return inputString;
    }

    public void keyPressed(KeyEvent e) {

    }

    public void keyReleased(KeyEvent e) {

    }

    public void keyTyped(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_9) {
            inputString += "9";
        }
        else if(e.getKeyCode() == KeyEvent.VK_8) {
            inputString += "8";
        }
        else if(e.getKeyCode() == KeyEvent.VK_7) {
            inputString += "7";
        }
        else if(e.getKeyCode() == KeyEvent.VK_6) {
            inputString += "6";
        }
        else if(e.getKeyCode() == KeyEvent.VK_5) {
            inputString += "5";
        }
        else if(e.getKeyCode() == KeyEvent.VK_4) {
            inputString += "4";
        }
        else if(e.getKeyCode() == KeyEvent.VK_3) {
            inputString += "3";
        }
        else if(e.getKeyCode() == KeyEvent.VK_2) {
            inputString += "2";
        }
        else if(e.getKeyCode() == KeyEvent.VK_1) {
            inputString += "1";
        }
        else if(e.getKeyCode() == KeyEvent.VK_0) {
            inputString += "0";
        }
        else if(e.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
            inputString = inputString.substring(0, inputString.length()-1);
        }
        else if(e.getKeyCode() == KeyEvent.VK_T) {
            inputString += "TRUE";
        }
        else if(e.getKeyCode() == KeyEvent.VK_F) {
            inputString += "FALSE";
        }
        else if(e.getKeyCode() == KeyEvent.VK_P) {
            inputString += "π";
        }
        else if(e.getKeyCode() == KeyEvent.VK_S) {
            inputString += "√";
        }
        else if(e.getKeyCode() == KeyEvent.VK_ENTER) {
            doneInputting = true;
        }
        else if(e.getKeyCode() == KeyEvent.VK_SLASH) {
            inputString += "/";
        }
        setAnswer(inputString);
    }
}