Java 暂停和恢复摆动计时器工作不正常

Java 暂停和恢复摆动计时器工作不正常,java,swing,user-interface,timer,Java,Swing,User Interface,Timer,我的程序是一个记忆游戏。每当单击互动程序时,计时器就会启动。我正在尝试创建一个菜单,用于暂停和恢复摆动计时器。停顿效果很好;但是,我遇到的问题是,每当我在暂停后恢复计时器时,它都会跳过四秒钟,而不是继续计时器。计时器的具体方法张贴在整个程序代码下面。以下是我目前拥有的: import java.awt.*; import java.awt.event.*; import java.util.ArrayList; import java.util.Arrays; import javax.swin

我的程序是一个记忆游戏。每当单击互动程序时,计时器就会启动。我正在尝试创建一个菜单,用于暂停和恢复摆动计时器。停顿效果很好;但是,我遇到的问题是,每当我在暂停后恢复计时器时,它都会跳过四秒钟,而不是继续计时器。计时器的具体方法张贴在整个程序代码下面。以下是我目前拥有的:

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Arrays;
import javax.swing.*;
import java.util.Collections;
import java.util.Calendar;
import java.time.*;

public class MemoryGame implements ActionListener {

private Timer cdTimer;  //Count down timer of 1.5 secs for unmatched pairs
private Timer swTimer;  //Main timer for the game

private int count = 0;
private long start = Calendar.getInstance().getTimeInMillis();
private long now;
private long elapsed;
boolean match = false;  //Determine if the cdTimer is running or not

private JToggleButton[] buttons;
private JToggleButton first;  //Variable for the first button to match
private JLabel time;  //Label to hold the 

private JMenuItem pause;
private JMenuItem resume;

ArrayList<ImageIcon> iconList = new ArrayList();
ArrayList<JToggleButton> retireButton = new ArrayList();  
ImageIcon icon = new ImageIcon("MemoryGame.png");

public MemoryGame() {

    JFrame jfrm = new JFrame("Memory Game");

    jfrm.setSize(1000, 1000);

    jfrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    jfrm.setIconImage(icon.getImage());

    time = new JLabel("Elapsed time is 00:00:00");

    GridLayout layout = new GridLayout(3,4);

    JPanel gamePanel = new JPanel();
    gamePanel.setLayout(layout);

    createIcons();  //set icons for the tiles

    buttons = new JToggleButton[12];

    for(int i = 0; i < buttons.length; i++) {
        JToggleButton btn = new JToggleButton(icon);

        buttons[i] = btn;

        buttons[i].addActionListener(this);

        gamePanel.add(buttons[i]);   
    }

    Collections.shuffle(Arrays.asList(buttons));
    Collections.shuffle(iconList);

    jfrm.add(gamePanel, BorderLayout.CENTER);
    time.setHorizontalAlignment(JLabel.CENTER);
    time.setVerticalAlignment(JLabel.CENTER);
    jfrm.add(time, BorderLayout.NORTH);

    //Create menus
    JMenuBar jm = new JMenuBar();
    JMenu action = new JMenu("Action");
    action.setMnemonic(KeyEvent.VK_A);

    JMenu gameTimer = new JMenu("Game Timer");
    gameTimer.setMnemonic(KeyEvent.VK_T);
    pause = new JMenuItem("Pause", KeyEvent.VK_P);
    pause.setAccelerator(KeyStroke.getKeyStroke("control P"));
    pause.setEnabled(false);
    pause.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent e){
            elapsed += now;
            swTimer.stop();
        }
    });
    resume = new JMenuItem("Resume", KeyEvent.VK_R);
    resume.setAccelerator(KeyStroke.getKeyStroke("control R"));
    resume.setEnabled(false);
    resume.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent e){
            timerContinue();
        }
    });
    gameTimer.add(pause);
    gameTimer.add(resume);
    action.add(gameTimer);

    JMenuItem reveal = new JMenuItem("Reveal", KeyEvent.VK_R);
    reveal.addActionListener(this);
    action.add(reveal);
    action.addSeparator();

    JMenuItem exit = new JMenuItem("Exit", KeyEvent.VK_X);
    exit.addActionListener(this);
    action.add(exit);

    JMenu help = new JMenu("Help");
    help.setMnemonic(KeyEvent.VK_H);
    JMenuItem viewHelp = new JMenuItem("View Help...", 
KeyEvent.VK_H);
    viewHelp.addActionListener(this);
    help.add(viewHelp);
    help.addSeparator();
    JMenuItem about = new JMenuItem("About", KeyEvent.VK_A);
    about.addActionListener(this);
    help.add(about);

    jm.add(action);
    jm.add(help);
    jfrm.setJMenuBar(jm);

    jfrm.setLocationRelativeTo(null);

    jfrm.setVisible(true);
}

public void actionPerformed(ActionEvent e){
    //this if makes sure the timer does not restart everytime a button is clicked
    if(retireButton.size() == 0){
        timerStart();
    }     

    if(swTimer.isRunning()){
        pause.setEnabled(true);
        resume.setEnabled(true);
    }

    //this if makes sure no button will be input during the 1.5 secs delay
    if(match == false){
        JToggleButton btn = (JToggleButton)e.getSource(); //take in button
        setIcon(btn);  
        resetIcon(btn);
        //this if makes btn equals the first button if it is null
        if(first == null){
            first = btn;
            return;
        }

        matching(first, btn);

        first = null;
    }
}

public void updateTime(){
    long temp = Calendar.getInstance().getTimeInMillis();
    time.setText("Elapsed time is " + formatTime((long) (temp - start)));
    now = temp - start;    
}

public void continueTime(){
    long temp = Calendar.getInstance().getTimeInMillis();
    time.setText("Elapsed time is " + formatTime((long) (temp - start)));
}

private void timerContinue(){
    ActionListener timerAL = new ActionListener(){
        public void actionPerformed(ActionEvent e){
            continueTime();
        }
    };

    //stop the timer if it is still running
    if (swTimer != null && swTimer.isRunning()) {
        swTimer.stop();
    }

    swTimer = new Timer(1000, timerAL);
    swTimer.setInitialDelay(0);
    swTimer.start();
}

public static String formatTime(long ms){
    long millis = ms % 1000;
    long x = ms / 1000;
    long seconds = x % 60;
    x /= 60;
    long minutes = x % 60;
    x /= 60;
    long hours = x % 24;

    return String.format("%02d:%02d:%02d", hours, minutes, seconds);
}

//Method to reset the button to game image when it is clicked for a second time
private void resetIcon(JToggleButton btn){
    if(!btn.isSelected()){
        btn.setIcon(icon);
    }
}

private void timerStart(){
    ActionListener timerAL = new ActionListener(){
        public void actionPerformed(ActionEvent e){
            updateTime();
        }
    };

    //stop the timer if it is still running
    if (swTimer != null && swTimer.isRunning()) {
        swTimer.stop();
    }

    swTimer = new Timer(1000, timerAL);
    swTimer.setInitialDelay(0);
    swTimer.start();
}

private void timerStop(){
    //if all 12 buttons are matched, then stop the timer
    if(retireButton.size() == 12){
        long stop = Calendar.getInstance().getTimeInMillis();
        time.setText("You finished in " + formatTime((long)(stop-start)));
        swTimer.stop();
    }
}

//set the icons for the tiles
private void setIcon(JToggleButton btn) {
    if(btn == buttons[0] || btn == buttons[1])
        btn.setIcon(iconList.get(0)); 

    else if(btn == buttons[2] || btn == buttons[3])
        btn.setIcon(iconList.get(1));

    else if(btn == buttons[4] || btn == buttons[5])
        btn.setIcon(iconList.get(2));

    else if(btn == buttons[6] || btn == buttons[7])
        btn.setIcon(iconList.get(3));

    else if(btn == buttons[8] || btn == buttons[9])
        btn.setIcon(iconList.get(4));

    else if(btn == buttons[10] || btn == buttons[11])
        btn.setIcon(iconList.get(5));
}

//match the two input buttons
private void matching(JToggleButton btn, JToggleButton btn2){
    if(btn.isSelected()){
        if(btn2.isSelected()){
            buttonDisable(btn, btn2); //disable all buttons besides btn, and btn2
            if(!btn.getIcon().toString().equals(btn2.getIcon().toString())){
                startTime(1, btn, btn2);  //start the 1.5 secs countdown
            }
            else {
                retirePair(btn, btn2);
                timerStop();
                buttonEnable(btn, btn2);
            }
        }
    }   
}

private void startTime(int countPassed, JToggleButton btn, JToggleButton btn2){
    ActionListener action = new ActionListener(){
        public void actionPerformed(ActionEvent e){
            if(count == 0){
                cdTimer.stop();
                match = false;  //resets match
                unflipPair(btn, btn2);  //reset tile to game image again
                buttonEnable(btn, btn2);
            }
            else
                count--;
            }

    };
    cdTimer = new Timer(500, action);
    cdTimer.start();
    match = true;
    count = countPassed;
}

//enable buttons other than btn and btn2
private void buttonEnable(JToggleButton btn, JToggleButton btn2){
    for(int i = 0; i < buttons.length; i++){
        if(buttons[i] != btn && buttons[i] != btn2)
            buttons[i].setEnabled(true);
    }
}

//disable buttons other than btn and btn2
private void buttonDisable(JToggleButton btn, JToggleButton btn2){
    for(int i = 0; i < buttons.length; i++){
        if(buttons[i] != btn && buttons[i] != btn2)
            buttons[i].setEnabled(false);
    }
}

private void unflipPair(JToggleButton btn, JToggleButton btn2){
    btn.setIcon(icon);
    btn2.setIcon(icon);
    btn.setEnabled(true);
    btn2.setEnabled(true);
    btn.setSelected(false);
    btn2.setSelected(false);
}

private void retirePair(JToggleButton btn, JToggleButton btn2){
    btn.setSelected(true);
    btn2.setSelected(true);
    btn.removeActionListener(this);
    btn2.removeActionListener(this);
    retireButton.add(btn);
    retireButton.add(btn2);
}

private void createIcons(){
    ImageIcon icon1 = new ImageIcon("1.png");
    ImageIcon icon2 = new ImageIcon("2.png");
    ImageIcon icon3 = new ImageIcon("3.png");
    ImageIcon icon4 = new ImageIcon("4.png");
    ImageIcon icon5 = new ImageIcon("5.png");
    ImageIcon icon6 = new ImageIcon("6.png");

    iconList.add(icon1);
    iconList.add(icon2);
    iconList.add(icon3);
    iconList.add(icon4);
    iconList.add(icon5);
    iconList.add(icon6);
}


public static void main(String args[]) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            if(args.length == 0) //java MemoryGame debug increases the string length to 1
                new MemoryGame();
            else
                new MemoryGame(2);
        }
    });
}
这是timerContinue方法:

public void continueTime(){
    long temp = Calendar.getInstance().getTimeInMillis();
    time.setText("Elapsed time is " + formatTime((long) (temp - start)));
}

private void timerContinue(){
    ActionListener timerAL = new ActionListener(){
        public void actionPerformed(ActionEvent e){
            continueTime();
        }
    };

    //stop the timer if it is still running
    if (swTimer != null && swTimer.isRunning()) {
        swTimer.stop();
    }

    swTimer = new Timer(1000, timerAL);
    swTimer.setInitialDelay(0);
    swTimer.start();
}
这是timeStart()方法:


因此,您可以捕获
start

private long start = Calendar.getInstance().getTimeInMillis();
当类第一次实例化时。。。我不确定这是一个好主意,但让我们顺其自然吧

当你暂停计时器时

pause.addActionListener(new ActionListener(){
    public void actionPerformed(ActionEvent e){
        elapsed += now;
        swTimer.stop();
    }
});
您可以捕获经过的时间

当你重新开始计时时

public void continueTime(){
    long temp = Calendar.getInstance().getTimeInMillis();
    time.setText("Elapsed time is " + formatTime((long) (temp - start)));
}

private void timerContinue(){
    ActionListener timerAL = new ActionListener(){
        public void actionPerformed(ActionEvent e){
            continueTime();
        }
    };

    //stop the timer if it is still running
    if (swTimer != null && swTimer.isRunning()) {
        swTimer.stop();
    }

    swTimer = new Timer(1000, timerAL);
    swTimer.setInitialDelay(0);
    swTimer.start();
}
您正在使用当前时间并减去
开始
,但
开始
从未重置,因此它仍然从首次初始化时开始计算

从概念上讲,“可暂停”时钟是具有两种重要状态的时钟

  • “当前”运行时。这是从启动/恢复到现在的时间
  • “上一次”运行时。这是允许计时器运行的总时间
所以。当你暂停时钟时,你需要做几件事

  • 计算此阶段的总运行时间-从开始到现在的时间
  • 将其添加到总“运行时间”中,该时间跟踪时钟允许运行的总时间
  • 重置开始时间(最好是像
    null
    ,这样比较明显)
  • 恢复后,您需要

  • 将当前时间存储为
    开始时间
    时间
  • 计算
    开始
    时间和现在之间的时间(时钟滴答作响时)
  • totalRunningTime
    添加到它,这将创建时钟的总运行时间

  • 简单因此,您可以捕获
    start

    private long start = Calendar.getInstance().getTimeInMillis();
    
    当类第一次实例化时。。。我不确定这是一个好主意,但让我们顺其自然吧

    当你暂停计时器时

    pause.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent e){
            elapsed += now;
            swTimer.stop();
        }
    });
    
    您可以捕获经过的时间

    当你重新开始计时时

    public void continueTime(){
        long temp = Calendar.getInstance().getTimeInMillis();
        time.setText("Elapsed time is " + formatTime((long) (temp - start)));
    }
    
    private void timerContinue(){
        ActionListener timerAL = new ActionListener(){
            public void actionPerformed(ActionEvent e){
                continueTime();
            }
        };
    
        //stop the timer if it is still running
        if (swTimer != null && swTimer.isRunning()) {
            swTimer.stop();
        }
    
        swTimer = new Timer(1000, timerAL);
        swTimer.setInitialDelay(0);
        swTimer.start();
    }
    
    您正在使用当前时间并减去
    开始
    ,但
    开始
    从未重置,因此它仍然从首次初始化时开始计算

    从概念上讲,“可暂停”时钟是具有两种重要状态的时钟

    • “当前”运行时。这是从启动/恢复到现在的时间
    • “上一次”运行时。这是允许计时器运行的总时间
    所以。当你暂停时钟时,你需要做几件事

  • 计算此阶段的总运行时间-从开始到现在的时间
  • 将其添加到总“运行时间”中,该时间跟踪时钟允许运行的总时间
  • 重置开始时间(最好是像
    null
    ,这样比较明显)
  • 恢复后,您需要

  • 将当前时间存储为
    开始时间
    时间
  • 计算
    开始
    时间和现在之间的时间(时钟滴答作响时)
  • totalRunningTime
    添加到它,这将创建时钟的总运行时间

  • 简单的
    start
    从未更改,尽管您计算了
    elasped
    时间,但您从未将其应用于计算。
    start
    从未更改,尽管您计算了
    elasped
    时间,但您从未将其应用于计算。非常感谢您解释此概念。我能够实现它。非常感谢你解释这个概念。我能够实现它。