【问题标题】:Stop timer with conditional only works first time?有条件的停止计时器只在第一次工作?
【发布时间】:2013-01-18 01:52:12
【问题描述】:

我正在写一个“谁想成为百万富翁”的游戏,我已经准备好了一切,只是计时器出了问题。

游戏是这样进行的:如果用户答对了问题,他/她会继续前进。如果没有,游戏就结束了,他们可以选择重新玩。

当游戏第一次运行时它很好,计时器会做它应该做的——从 30 秒开始倒计时,显示秒数。

但是,当用户单击“再次播放”按钮时,前一个计时器将继续使用新计时器。像这样:

-timerA 距离用户丢失还有 20 秒(用 a 表示)。

-timerB 在下一次游戏开始时开始(用 b 表示)。

输出:20a 29b 19a 28b 18a 27b 17a 26b ....... 2a 11b 1a 10b 9b 8b 7b 6b 5b 4b 3b 2b 1b

这是我的计时器类,称为 CountDown:

  import java.util.Timer;
  import java.util.TimerTask;

  public class CountDown {

      static Timer timer;
      public static int seconds = 30;

      public CountDown() {
          timer = new Timer();
          timer.schedule(new DisplayCountdown(), 0, 1000);
      }

      class DisplayCountdown extends TimerTask {

          int seconds = 30;

          public void run() {

                  if (seconds == 0) {
                      timer.cancel();
                      timer.purge();
                      return;
                  }

              if (seconds > 0) {
                  PlayFrame.timer.setText("" + seconds); //jLabel used to display seconds
                  seconds--;
                  if (seconds < 30) {
                      if (PlayFrame.right == true) { //check if question was answered correctly
                          System.out.print("true"); //testing purposes
                          PlayFrame.right = false;
                          PlayFrame.showQuestion();
                          PlayFrame.startTimer();
                          seconds = 0;
                          //break;
                      }
                      else if (PlayFrame.right == false) {
                          //break;
                      }
                  }      

                  else if (seconds == 0) { //if time runs out its automatic wrong answer
                      PlayFrame.wrong();
                      //break;
                  }      

                  else {
                      PlayFrame.wrong();
                      PlayFrame.timer.setText(null);
                      timer = new Timer();
                      //break;
                  }
              }
              System.out.println(seconds); // for testing purposes only
          }
      }
  }

这是我的一些 PlayFrame:

  import java.awt.Color;
  import java.util.Timer;

  public class PlayFrame extends javax.swing.JFrame {

      public static void wrong() {
          //determines which losing frame to show
          if (count <= 2){
              LossLevel0 L0 = new LossLevel0();
              L0.setVisible(true);
          }
          else if (count > 2 && count <= 6 && count != 6){
              LossLevel1 L1 = new LossLevel1();
              L1.setVisible(true);
          }
          else {
              LossLevel1 L1 = new LossLevel1();
              L1.setVisible(true);
          }
          //"supposed" to stop the timer
          CountDown.timer.cancel();
          CountDown.timer.purge();
      }

      public static void startTimer() {
          //creates new CountDown object and timer, also resets seconds
          CountDown countdown = new CountDown();
          CountDown.timer = new Timer();
          CountDown.seconds = 30;
      }

我想问题可能出在我重新开始游戏的时候。唯一的代码是我在游戏开始之前将所有变量重置回其原始状态。像这样:

    // Reset Everything
    PlayFrame.count = 0;
    PlayFrame.answer = new String();
    PlayFrame.count = 0;
    PlayFrame.right = false;
    PlayFrame.winnings = 0;
    CountDown.seconds = 30;
    CountDown.timer = new Timer();
    CountDown.timer.cancel();
    CountDown.timer.purge();

请帮忙,如果您需要更多信息,请询问!

【问题讨论】:

    标签: java netbeans timer timertask


    【解决方案1】:

    您不应该在 Swing 应用程序中使用 java.util.Timer。对于这些,您应该使用javax.swing.Timer,因为这将尊重 Swing 事件线程。因此,您的问题没有实际意义,我建议您将所有计时代码都扔掉并尝试使用正确的计时器。你可以在这里找到教程:Swing Timer Tutorial

    接下来,您需要摆脱代码正在使用的所有静态方法和字段,并将它们更改为实例字段和方法。

    在 JLabel 中显示剩余时间的 Swing Timer 示例:

    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import javax.swing.*;
    
    public class TimerExample {
    
       private static void createAndShowGui() {
          Gui mainPanel = new Gui();
    
          JFrame frame = new JFrame("TimerExample");
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.getContentPane().add(mainPanel);
          frame.pack();
          frame.setLocationByPlatform(true);
          frame.setVisible(true);
       }
    
       public static void main(String[] args) {
          SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                createAndShowGui();
             }
          });
       }
    }
    
    class Gui extends JPanel {
       private static final long serialVersionUID = 1L;
       private static final String PRESS_BUTTON = "Press Button ";
       private static final String PRESS_BUTTON_AGAIN = "Press Button Again Within %02d Seconds!";
       private static final String YOU_LOSE = "You Lose!";
       private static final String YOU_WIN = "You Win!";
       private static final int PREF_W = 250;
       private static final int PREF_H = 100;
       private static final int TOTAL_SECONDS = 20;
       private static final int ONE_SECOND = 1000;
    
       private int elapsedSeconds = 0;
       private JLabel timerLabel = new JLabel(PRESS_BUTTON);
       private JButton button = new JButton("Button");
       private Timer myTimer;
    
       public Gui() {
          JPanel btnPanel = new JPanel();
          btnPanel.add(button);
    
          setLayout(new BorderLayout());
          add(btnPanel, BorderLayout.CENTER);
          add(timerLabel, BorderLayout.SOUTH);
    
          button.addActionListener(new ActionListener() {
    
             @Override
             public void actionPerformed(ActionEvent arg0) {
                if (myTimer != null && myTimer.isRunning()) {
                   myTimer.stop();
                   myTimer = null;
                   timerLabel.setText(YOU_WIN);               
                } else {
                   elapsedSeconds = 0;
                   myTimer = new Timer(ONE_SECOND, new TimerListener());
                   myTimer.start();
                   String text = String.format(PRESS_BUTTON_AGAIN, TOTAL_SECONDS); 
                   timerLabel.setText(text);
                }
             }
          });
       }
    
       @Override
       public Dimension getPreferredSize() {
          return new Dimension(PREF_W, PREF_H);
       }
    
       private class TimerListener implements ActionListener {
          @Override
          public void actionPerformed(ActionEvent e) {
             elapsedSeconds++;
    
             if (elapsedSeconds == TOTAL_SECONDS) {
                myTimer.stop();
                timerLabel.setText(YOU_LOSE);
             } else {
                String text = String.format(PRESS_BUTTON_AGAIN, TOTAL_SECONDS - elapsedSeconds);
                timerLabel.setText(text );
             }
          }
       }
    }
    

    【讨论】:

    • 那并不理想。我的一切正常,只是前一个计时器不会停止,即使我调用 cancel() 和 purge() 也是如此。而且(是的,我是新手)我对 ActionListeners 感到困惑;因为我是用 Netbeans 编写的,所以它会自动为我完成。
    • @CodeAddict:这不是 理想 与否的问题。这是错误的,可能行不通,纯粹而简单。如果 ActionListener 让您感到困惑,我在上面链接到的同一个教程有一节介绍如何使用 ActionListener。当然,如果您遇到困难,您可以随时返回这里展示您的尝试。
    • @CodeAddict 我也是一个相当新的程序员,我不得不说 Swing Timer 是要走的路。我只用过一次,但很简单。即使我没有使用 GUI,我也几乎会在 util Timer 上使用它。你真的应该听听气垫船的建议。这家伙给了一个非常好的解释albertattard.blogspot.com/2008/09/…
    • @David Kroukamp 我理解这个论点,但我想我可能会选择将 Swing Timer 与 SwingWorker 一起使用,以防止长时间运行的任务在 EDT 上结束。但是,您是对的,使用 util Timer 也可以避免这种情况。
    • @DavidKroukamp:在 EDT 上运行的任何东西都是如此。摆动计时器严格用于计时,仅此而已。如果代码调用一个长时间运行的进程,那么它需要在后台线程上。 Swing Timer 的优点是它的 ActionListener 代码在 EDT 上运行,使您不必排队 Runnable。另一方面,还有 ScheduledThreadExecutor 有时比 util Timer 更适合用于时间关键代码。
    【解决方案2】:

    我建议将 Timer 声明移到 JFrame 中,然后在每次需要计时器时创建“DisplayCountdown”类的新实例,并移动“timer.schedule(new DisplayCountdown(), 0 , 1000);"在别处排队。

    如果你purge一个定时器对象,它会被完全重置,所以你不需要创建一个新的定时器对象,只需要添加一个新的TimerTask。

    【讨论】:

    • 创建“DisplayCountdown”类的新实例意味着什么语法?如果我将timer.schedule 行移到run 块中会有帮助吗?以及如何添加新的 TimerTask?抱歉,Timer 类让我对 purge() 和 cancel() 方法感到困惑
    • 所以在主应用程序中,我认为您将其称为 PlayFrame,您将创建一个私有 Timer 变量,并且每当您启动 Timer 时,添加以下行:“timer.schedule(new DisplayCountdown( ), 0, 1000);”。当 Countdown 结束时,如果超时,它会自动清除,所以除了 DisplayCountdown 类的运行和 PlayFrame 类的错误函数之外,您不需要在任何地方调用 purge。
    • 我得到an enclosing instance that contains CountDown.DisplayCountdown is required(因为 DisplayCountdown 在 CountDown 类中)。好的,但是如果答案正确,我希望计时器完全消失,永远不要再使用它,并制作一个新的
    • 使用取消和清除功能与创建一个新计时器的作用完全相同,但应该更好地清除存储的内存。在多线程中,使用提供的清理函数总是一个好主意,比如流。
    • 据我所知,内存并没有被清除。它一直在继续,直到它到达0才会停止。就像一个女人在完成一项任务,直到她达到目标才会停止。我不熟悉最后一句话是在谈论寿。
    【解决方案3】:

    已解决,感谢 sage88 的链接! http://albertattard.blogspot.com/2008/09/practical-example-of-swing-timer.html

    关于摇摆计时器的更多帮助(用于该主题的未来搜索)http://www.asjava.com/swing/java-timer-tutorial/

    public static void startTimer() {
        listener = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                System.out.print("action");
                timerLabel.setText("" + seconds);
                seconds--;
                System.out.println(seconds);
                if (seconds < 0){
                    System.out.print("zero");
                    wrong();
                }
            }
        };
        displayTimer = new Timer(1000, listener);
        displayTimer.setInitialDelay(1);
        displayTimer.start();
    
        if (right == true){
            System.out.print("true");
            displayTimer.stop();
            right = false;
            seconds = 30;
            displayTimer = new Timer(10000, listener);
            displayTimer.setDelay(10000);
            displayTimer.setInitialDelay(1);
            displayTimer.start();
        }
        else if (right == null){
            System.out.print("null");
            displayTimer.stop();
            seconds = 30;
            displayTimer = new Timer(10000, listener);
            displayTimer.setInitialDelay(1);
            displayTimer.setDelay(10000);
            displayTimer.start();
        }
    }
    

    【讨论】:

    • 不客气!它帮助了我,所以我想我会把它传递下去。他对 SwingWorker 做了一些很好的报道,你也可以看看。真的很有帮助。
    猜你喜欢
    • 1970-01-01
    • 2021-09-27
    • 1970-01-01
    • 1970-01-01
    • 2018-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多