Создание основанного на графическом интерфейсе хронометра (или секундомера)

Я потратил некоторое время на то, чтобы поработать с программой, показывающей истекшее или оставшееся время, с которого пользователь нажимает кнопку запуска, подобно секундомеру или хронометру, который измеряет время до тех пор, пока вы не остановитесь и не выполните сброс. Другие примеры измерения прошедшего времени - это время прохождения круга в гоночных играх и ограничения по времени с миллисекундами в других играх.

Я столкнулся с некоторыми проблемами, потому что мой собственный секундомер не работает с той же скоростью, что и фактическое время. Мой таймер работает дольше, чем одна секунда, чтобы запустить одну секунду вниз или вверх.

Код прямо здесь: (GUI работает отлично; яЯ больше обеспокоен тем, как управлять значениями, чтобы показать истекшее время таким образом, чтобы за каждую секунду прошло время, отображаемое наJLabel на одну секунду меньше. Я не могу изменить аргументс перешли вThread.sleep потому что это сделает таймер намного хуже.)

import javax.swing.*;

import java.awt.event.*;
import java.awt.*;
import java.text.DecimalFormat;
import java.util.concurrent.*;

public class StopwatchGUI3 extends JFrame 
{

    private static final long serialVersionUID = 3545053785228009472L;

    // GUI Components
    private JPanel panel;
    private JLabel timeLabel;

    private JPanel buttonPanel;
    private JButton startButton;
    private JButton resetButton;
    private JButton stopButton;

    // Properties of Program.
    private byte centiseconds = 0;
    private byte seconds = 30;
    private short minutes = 0;

    private Runnable timeTask;
    private Runnable incrementTimeTask;
    private Runnable setTimeTask;
    private DecimalFormat timeFormatter;
    private boolean timerIsRunning = true;

    private ExecutorService executor = Executors.newCachedThreadPool();

    public StopwatchGUI3()
    {
        panel = new JPanel();
        panel.setLayout(new BorderLayout());

        timeLabel = new JLabel();
        timeLabel.setFont(new Font("Consolas", Font.PLAIN, 13));
        timeLabel.setHorizontalAlignment(JLabel.CENTER);
        panel.add(timeLabel);


        buttonPanel = new JPanel();
        buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER));

        startButton = new JButton("Start");
        startButton.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                if (!timerIsRunning)
                    timerIsRunning = true;

                executor.execute(timeTask);
            }
        });
        buttonPanel.add(startButton);

        resetButton = new JButton("Reset");
        resetButton.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                timerIsRunning = false;

                centiseconds = 0;
                seconds = 30;
                minutes = 0;

                timeLabel.setText(timeFormatter.format(minutes) + ":" 
                        + timeFormatter.format(seconds) + "." 
                        + timeFormatter.format(centiseconds));
            }
        });

        buttonPanel.add(resetButton);

        stopButton = new JButton("Stop");
        stopButton.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                timerIsRunning = false;
            }
        });

        buttonPanel.add(stopButton);


        panel.add(buttonPanel, BorderLayout.SOUTH);


        timeFormatter = new DecimalFormat("00");

        timeTask = new Runnable(){
            public void run()
            {
                while(timerIsRunning)
                {
                    executor.execute(incrementTimeTask);

                    try
                    {
                        Thread.sleep(10);
                    }
                    catch (InterruptedException ex)
                    {
                        ex.printStackTrace();
                    }
                 }
            }
        };

        incrementTimeTask = new Runnable(){
            public void run()
            {
                if (centiseconds > 0)
                    centiseconds--;
                else
                {
                    if (seconds == 0 && minutes == 0)
                        timerIsRunning = false;
                    else if (seconds > 0)
                    {
                        seconds--;
                        centiseconds = 99;
                    }
                    else if (minutes > 0)
                    {
                        minutes--;
                        seconds = 59;
                        centiseconds = 99;
                    }
                }

                executor.execute(setTimeTask);
            }
        };

        setTimeTask = new Runnable(){
            public void run()
            {
                timeLabel.setText(timeFormatter.format(minutes) + ":" 
                        + timeFormatter.format(seconds) + "." 
                        + timeFormatter.format(centiseconds));
            }
        };

        timeLabel.setText(timeFormatter.format(minutes) + ":" 
                + timeFormatter.format(seconds) + "." 
                + timeFormatter.format(centiseconds));

        add(panel);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setTitle("StopwatchGUI.java");

        pack();
        setVisible(true);
    }

    public static void main(String[] args) 
    {
        new StopwatchGUI3();
    }
}

Там'Должен быть другой способ синхронизировать таймер с реальным временем, точно так же, как настоящий секундомер, вместо того, чтобы полагаться на три отдельных потока, которых я считаю слишком много для такого большого проекта программирования, но хорошо на начальном уровне для сейчас. (о, кстати,DecimalFormat Класс должен правильно отформатировать числа, как настоящий секундомер, хотя для округления нет десятичных значений. Это'До тех пор, пока я не опубликовал это, существует только текстовый классSimpleDateFormat.)

Другими словами, я хочу, чтобы эта программа была просто настоящим секундомером. Если это не так, то как, например, создать или использовать секундомер в играх Java?

Ответы на вопрос(2)

Ваш ответ на вопрос