Java - Aktualisierung des vorhandenen Stoppuhrcodes mit Countdown

@ HovercraftFullofEels hat mir freundlicherweise geholfen, indem es mir die Basis für den folgenden Code zur Verfügung stellte, an dem ich einige Änderungen vorgenommen habe (gekennzeichnet durch "vollständig hinzugefügte Zeile" -Kommentare und den riesigen Kommentar am Ende, der irgendwo anzuordnenden Code enthält) die Datei)

Die ursprüngliche Datei war eine einfache Stoppuhr, und meine Änderungen umfassen 3 JTextFields.das dauert in Minuten, Sekunden und CENTIseconds (1 Centisekunde = 1/100 Sekunde). Ich möchte auch einen "Submit" -Button einfügen, mit dem das Programm die Eingabe dieser 3 Textfelder lesen kann. Ich habe den Code für die Methode geschrieben, die aufgerufen werden soll, wenn auf "Submit" geklickt wird (im riesigen Kommentar am Ende enthalten). Wenn ich darauf klicke, möchte ich, dass das Programm sofort einen Countdown von diesen Werten starteton dem Zeitpunkt an, an dem die Stoppuhr gestartet wur anstatt ab dem Zeitpunkt des Klickens auf die Schaltfläche. Wenn beispielsweise die Stoppuhr 20 Minuten lang läuft, nachdem der Benutzer auf "Senden" mit einer eingegebenen Zeit von 25 Minuten geklickt hat, wird ein Countdown von 5 Minuten gestartet.

Wenn dies immer noch verwirrend ist, müssen Sie nur wissen, dass meine Methode mit einer Zeile endet, die in Millisekunden angibt, wo der Countdown beginnen soll. An diesem Punkt soll der Countdown die Stoppuhr ERSETZEN. Ich möchte auch die Schaltflächen "Pause" und "Stopp" entfernen, aber nicht die Schaltfläche "Start" (Sie würden meinen, sie wären leicht zu entfernen, aber ich habe das entfernt, was ich für angemessen hielt und beim Kompilieren einen Fehler erhalten habe) und ersetzen sie mit dem einzigen "Submit" -Button.

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.Font;                     //line completely added
import javax.swing.*;

@SuppressWarnings("serial")
public class MyTimer2 extends JPanel implements GuiTimer {
    private static final String TIME_FORMAT = "%02d:%02d:%02d";   //changed from "%03d:%03d"
    private static final int EXTRA_WIDTH = 50;
    private JLabel timerLabel = new JLabel();
    private TimerControl timerControl = new TimerControl(this);

    JTextField minsField, secsField, centisField;     //line completely added - should this be private?
    JLabel colon, period;                             //line completely added - should this be private?

    public MyTimer2() {
        JPanel topPanel = new JPanel();
        topPanel.add(timerLabel);

        timerLabel.setFont(new Font("Arial", Font.BOLD, 64));     //line completely added

        minsField = new JTextField("", 2);
        secsField = new JTextField("", 2);
        centisField = new JTextField("", 2);

        colon = new JLabel(":");
        period = new JLabel(".");

        JPanel centerPanel = new JPanel();
        centerPanel.add(minsField);          //line completely added
        centerPanel.add(colon);              //line completely added
        centerPanel.add(secsField);          //line completely added
        centerPanel.add(period);             //line completely added
        centerPanel.add(centisField);        //line completely added

        JPanel bottomPanel = new JPanel();                              //line completely added
        bottomPanel.add(new JButton(timerControl.getStartAction()));    //changed from centerPanel
        bottomPanel.add(new JButton(timerControl.getStopAction()));     //changed from centerPanel

        setLayout(new BorderLayout());
        add(topPanel, BorderLayout.PAGE_START);
        add(centerPanel, BorderLayout.CENTER);
        add(bottomPanel, BorderLayout.PAGE_END);   //line completely added

        setDeltaTime(0);
    }

    @Override
    public void setDeltaTime(int delta) {
        int mins = (int) delta / 60000;                                          // line completely added
        int secs = ((int) delta % 60000) / 1000;                                 // %60000 added
        int centis = ((int) delta % 1000) / 10;                                  // / 10 added
        timerLabel.setText(String.format(TIME_FORMAT, mins, secs, centis));      // mins added; mSecs changed to centis
    }

    @Override
    public Dimension getPreferredSize() {
        Dimension superSz = super.getPreferredSize();
        if (isPreferredSizeSet()) {
            return superSz;
        }
        int prefW = superSz.width + EXTRA_WIDTH;
        int prefH = superSz.height;
        return new Dimension(prefW, prefH);
    }

    private static void createAndShowGui() {
        MyTimer2 mainPanel = new MyTimer2();

        JFrame frame = new JFrame("MyTimer2");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  //changed from DISPOSE_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();
            }
        });
    }
}

interface GuiTimer {
    public abstract void setDeltaTime(int delta);
}

@SuppressWarnings("serial")
class TimerControl {
    private static final int TIMER_DELAY = 10;
    private long startTime = 0;
    private long pauseTime = 0;
    private Timer timer;
    private GuiTimer gui;
    private StartAction startAction = new StartAction();
    private StopAction stopAction = new StopAction();

    public TimerControl(GuiTimer gui) {
        this.gui = gui;
    }

    public Action getStopAction() {
        return stopAction;
    }

    public Action getStartAction() {
        return startAction;
    }

    enum State {
        START("Start", KeyEvent.VK_S), 
        PAUSE("Pause", KeyEvent.VK_P);
        private String text;
        private int mnemonic;

        private State(String text, int mnemonic) {
            this.text = text;
            this.mnemonic = mnemonic;
        }

        public String getText() {
            return text;
        }

        public int getMnemonic() {
            return mnemonic;
        }
    };

    private class StartAction extends AbstractAction {
        private State state;

        public StartAction() {
            setState(State.START);
        }

        public final void setState(State state) {
            this.state = state;
            putValue(NAME, state.getText());
            putValue(MNEMONIC_KEY, state.getMnemonic());
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (state == State.START) {
                if (timer != null && timer.isRunning()) {
                    return; // the timer's already running
                }
                setState(State.PAUSE);
                if (startTime <= 0) {
                    startTime = System.currentTimeMillis();
                    timer = new Timer(TIMER_DELAY, new TimerListener());
                } else {
                    startTime += System.currentTimeMillis() - pauseTime;
                }
                timer.start();
            } else if (state == State.PAUSE) {
                setState(State.START);
                pauseTime = System.currentTimeMillis();
                timer.stop();
            }
        }
    }

    private class StopAction extends AbstractAction {
        public StopAction() {
            super("Stop");
            int mnemonic = KeyEvent.VK_T;
            putValue(MNEMONIC_KEY, mnemonic);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (timer == null) {
                return;
            }
            timer.stop();
            startAction.setState(State.START);
            startTime = 0;
        }
    }

    private class TimerListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            long time = System.currentTimeMillis();
            long delta = time - startTime;
            gui.setDeltaTime((int) delta); 
        }
    }

}

/*not sure where this will go, but this is the code for clicking "Submit"   

   //upon clicking "Submit"...
   public void actionPerformed(ActionEvent e)
   {      
      String minsStr = minsField.getText();
      String secsStr = secsField.getText();
      String centisStr = centisField.getText();
      int minsInput = Integer.parseInt(minsStr);
      int secsInput = Integer.parseInt(secsStr);
      int centisInput = Integer.parseInt(centisStr);

      long millis = minsInput * 60000 + secsInput * 1000 + centisInput * 10;

      long millisCountdown = millis - delta;   //where "delta" is elapsed milliseconds

      if(millisCountdown < 0)
          JOptionPane.showMessageDialog("Invalid time entered.");

      else
          //then immediately change from stopwatch to countdown beginning from millisCountdown and ending at 00:00:00

      minsField.setText("");     //clear minsField
      secsField.setText("");     //clear secsField
      centisField.setText("");   //clear centisField
   }
*/

Wenn mir jemand dabei helfen könnte, würde ich es sehr schätzen. Leider verstehe ich den Großteil des Hovercraft-Codes nicht, sodass ich keine Ahnung habe, wohin ich gehen soll, nachdem was ich bereits getan habe.

Vielen Dank

EDIT: Hier ist die aktualisierte Version des @ MadProgrammer-Codes:

import java.awt.EventQueue;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Font;
import java.time.Duration;
import java.time.LocalTime;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class StopWatch {

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

    public StopWatch() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static class TestPane extends JPanel {

        protected static final String TIME_FORMAT = "%02d:%02d.%02d";

        private LocalTime startTime;
        private LocalTime targetTime;

        private JLabel label;
        private JTextField minsField, secsField, centisField;
        private JButton start, submit;

        private Timer timer;

        public TestPane() {
            JPanel topRow = new JPanel();
            JPanel centerRow = new JPanel();
            JPanel bottomRow = new JPanel();

            label = new JLabel(formatDuration(Duration.ofMillis(0)));
            topRow.add(label);

            minsField = new JTextField("", 2);
            secsField = new JTextField("", 2);
            centisField = new JTextField("", 2);
            centerRow.add(minsField);
            centerRow.add(secsField);
            centerRow.add(centisField);

            start = new JButton("Start");
            start.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (!timer.isRunning()) {
                        startTime = LocalTime.now();
                        timer.start();
                    }
                }
            });

            bottomRow.add(start);

            submit = new JButton("Submit");
            submit.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                if (timer.isRunning()) {
                        timer.stop();

                        Duration runningTime = Duration.between(startTime, LocalTime.now());
                        // Subtract the required amount of time from the duration

                        String minsStr = minsField.getText();
                        String secsStr = secsField.getText();
                        String centisStr = centisField.getText();

                        if(minsStr.matches("\\d+$") && secsStr.matches("\\d+$") && centisStr.matches("\\d+$"))
                        {                       
                           int minsInput = Integer.parseInt(minsStr);
                           int secsInput = Integer.parseInt(secsStr);
                           int centisInput = Integer.parseInt(centisStr);

                           if(minsInput >= 0 && secsInput >= 0 && secsInput < 60 && centisInput >= 0 && centisInput < 100)
                           {

                              long millis = minsInput * 60000 + secsInput * 1000 + centisInput * 10;

                              runningTime = runningTime.minusMillis(millis);

                              timer.start();

                              // No negative times
                              if (runningTime.toMillis() > 0)
                              {
                                  // When the timer is to end...
                                  targetTime = LocalTime.now().plus(runningTime);
                              }

                              else
                              {
                                 JOptionPane.showMessageDialog(null, "Invalid time entered.");
                              }
                           }

                           else
                           {
                              timer.start();
                              JOptionPane.showMessageDialog(null, "Invalid time entered.");
                           }
                        }

                        else
                        {
                           timer.start();
                           JOptionPane.showMessageDialog(null, "Invalid time entered.");
                        }

                        minsField.setText("");
                        secsField.setText("");
                        centisField.setText("");
                    }
                }
            });

            bottomRow.add(submit);

            timer = new Timer(10, new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    if (targetTime != null) {
                        Duration duration = Duration.between(LocalTime.now(), targetTime);
                        if (duration.toMillis() <= 0) {
                            duration = Duration.ofMillis(0);
                            timer.stop();
                            targetTime = null;
                        }
                        label.setText(formatDuration(duration));
                    } else {
                        // Count up...
                        Duration duration = Duration.between(startTime, LocalTime.now());
                        label.setText(formatDuration(duration));
                    }
                }
            });

            setLayout(new BorderLayout());

            label.setFont(new Font("Arial", Font.BOLD, 64));

            add(topRow, BorderLayout.PAGE_START);
            add(centerRow, BorderLayout.CENTER);
            add(bottomRow, BorderLayout.PAGE_END);
        }

        protected String formatDuration(Duration duration) {
            long mins = duration.toMinutes();
            duration = duration.minusMinutes(mins);
            long seconds = duration.toMillis() / 1000;
            duration = duration.minusSeconds(seconds);
            long centis = duration.toMillis() / 10;

            return String.format(TIME_FORMAT, mins, seconds, centis);
        }
    }
}

Antworten auf die Frage(2)

Ihre Antwort auf die Frage