多个Swing计时器导致多个动作发生 [英] Multiple Swing Timers Cause Multiple Actions to Happen

查看:131
本文介绍了多个Swing计时器导致多个动作发生的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做一个Java项目,我必须制作一个包含多个从用户输入时间倒计时的计时器的GUI。当我只创建一个计时器时,程序工作正常,但是当我尝试包含多个计时器时,每个计时器将根据计时器的数量更快地倒计时。我认为问题是由每次swing定时器调用一个动作时多次调用ActionListener引起的,但我不知道如何解决这个问题。

I'm doing a Java project where I have to make a GUI that contains multiple timers that countdown from a user input time. When I create only one timer, the program works fine, but when I try to include multiple timers, each timer will countdown faster based on how many timers there are. I think the problem is being caused by the ActionListener being called multiple times each time the swing timer calls for an action, but I do not know how to solve that problem.

这是我的CountDownTimer类,它包含计时器的属性和方法:

Here is my CountDownTimer class that contains the attributes and methods for the timer:

package pack1;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner;

/*******************************************************************************
 * Class that contains the methods needed to create a timer that counts down
 * @version January 2014, Project 1
 ********************************************************************************/
public class CountDownTimer {
    /** Amount of hours that are being counted down in the timer */
    int hours;
    /** Amount of minutes that are being counted down in the timer */
    int minutes;
    /** Amount of seconds that are being counted down in the timer */
    int seconds;

    /** Boolean that determines if the add method will work. It is changed with the toggleSuspend method */
    static boolean toggle = false;

    /*****************************************************************************************
     * Default constructor that creates a CountDownTimer object with no time contained in it
     *****************************************************************************************/
    public CountDownTimer() {
        hours = 0;
        minutes = 0;
        seconds = 0;
    }

    /*********************************************************************************************
     * Constructor that uses the input amount of hours, minutes, and seconds to count down from
     * 
     * Does not allow time that is negative or allow seconds or minutes that are over 60
     * @param hours amount of hours that will be counted down from
     * @param minutes amount of minutes that will be counted down from
     * @param seconds amount of seconds that will be counted down from
     *********************************************************************************************/
    public CountDownTimer(int hours, int minutes, int seconds) {
        super();

        // doesn't allow negative minutes, seconds, or hours
        if (seconds < 0 || minutes < 0 || hours < 0) {
            throw new IllegalArgumentException("Time cannot be negative");
        }
        // doesn't allow seconds that are higher than 60
        if (seconds >= 60) {
            throw new IllegalArgumentException(
                    "Cannot have more than 60 seconds");
        }
        // doesn't allow minutes that are higher than 60
        if (minutes >= 60) {
            throw new IllegalArgumentException(
                    "Cannot have more than 60 minutes");
        }
        this.hours = hours;
        this.minutes = minutes;
        this.seconds = seconds;
    }
    /*********************************************************************
     * Constructor that takes minutes and seconds, and sets hours to zero
     * also doesn't allow minutes or seconds to be negative or above 60
     * @param minutes amount of minutes that will be counted down from
     * @param seconds amount of seconds that will be counted down from
     *************************************************************************/
    public CountDownTimer(int minutes, int seconds) {
        super();
        // doesn't allow seconds minutes or hours to be negative
        if (seconds < 0 || minutes < 0 || hours < 0) {
            throw new IllegalArgumentException("Time cannot be negative");
        }
        // doesn't allow seconds to be greater than 60
        if (seconds >= 60) {
            throw new IllegalArgumentException(
                    "Cannot have more than 60 seconds");
        }
        // doesn't allow minutes to be greater than 60
        if (minutes >= 60) {
            throw new IllegalArgumentException(
                    "Cannot have more than 60 minutes");
        }

        this.hours = 0;
        this.minutes = minutes;
        this.seconds = seconds;
    }

    /***********************************************************************
     * Constructor that only takes seconds and sets hours and minutes to 0
     * does not allow the seconds to be above 60 or negative
     * @param seconds amount of seconds that will be counted down from
     *************************************************************************/
    public CountDownTimer(int seconds) {
        super();

        // doesn't allow seconds minutes or hours to be negative
        if (seconds < 0 || minutes < 0 || hours < 0) {
            throw new IllegalArgumentException("Time cannot be negative");
        }
        // doesn't allow seconds to be greater than 60
        if (seconds >= 60) {
            throw new IllegalArgumentException(
                    "Cannot have more than 60 seconds");
        }
        this.hours = 0;
        this.minutes = 0;
        this.seconds = seconds;
    }


    /** 
     * Constructor that clones one CountDownTimer object into a new CountDownTimer object
     * @param other The CountDownTimer object that is being cloned
     * */
    public CountDownTimer(CountDownTimer other) {
        this.hours = other.hours;
        this.minutes = other.minutes;
        this.seconds = other.seconds;
    }

    /*******************************************************************************************************************************
     * Constructor that converts a string in the format of "00:00:00" into seconds minutes and hours so it can be counted down from
     * @param startTime String that is converted into seconds minutes and hours
     *******************************************************************************************************************************/
    public CountDownTimer(String startTime) {
        // Separates the seconds minutes and hours into an array
        String[] parts = startTime.split(":");
        // if the array has only one cell, that means only seconds were input
        if (parts.length == 1) {
            seconds = Integer.parseInt(parts[0]);
        }
        // if the array has only 2 cells that means there is only minutes and seconds input
        if (parts.length == 2) {
            minutes = Integer.parseInt(parts[0]);
            seconds = Integer.parseInt(parts[1]);
        }
        // if the array has 3 cells that means there is seconds minutes and hours input
        if (parts.length == 3) {
            hours = Integer.parseInt(parts[0]);
            minutes = Integer.parseInt(parts[1]);
            seconds = Integer.parseInt(parts[2]);
        }
        // doesn't allow seconds minutes or hours to be negative
        if (seconds < 0 || minutes < 0 || hours < 0) {
            throw new IllegalArgumentException("Time cannot be negative");
        }
        // doesn't allow seconds to be greater than or equal to 60
        if (seconds >= 60) {
            throw new IllegalArgumentException(
                    "Cannot have more than 60 seconds");
        }
        // doesn't allow minutes to be greater than or equal to 60
        if (minutes >= 60) {
            throw new IllegalArgumentException(
                    "Cannot have more than 60 minutes");
        }
    }

    /**************************************************************************************************
     * Method that returns true or false based on whether or not two CountDownTimer objects are equal
     * @param other Object that is being compared to another CountDownTimer
     **************************************************************************************************/
    public boolean equals(Object other) {
        // converts the two objects to seconds then compares them
        if (this.convertToSeconds() == ((CountDownTimer) other)
                .convertToSeconds())
            return true;
        return false;
    }

    /********************************************************************************
     * Returns a boolean based on whether two CountDownTimers, t1 and t2, are equal
     * @param t1 first CountDownTimer being compared
     * @param t2 second CountDownTimer being compared
     ********************************************************************************/
    public static boolean equals(CountDownTimer t1, CountDownTimer t2) {
        // converts the two objects to seconds and then compares them
        if (t1.convertToSeconds() == t2.convertToSeconds())
            return true;
        return false;
    }

    /************************************************************************************************
     * Compares to CountDownTimer objects and returns an int 1, 0, or -1 based on whether the first
     * object is greater than, equal to, or less than the CountDownTimer in the parameter
     * @param other CountDownTimer that is being compared
     *************************************************************************************************/
    public int compareTo(CountDownTimer other) {
        if (this.convertToSeconds() > other.convertToSeconds())
            return 1;
        else if (this.convertToSeconds() < other.convertToSeconds())
            return -1;
        return 0;
    }

    /**************************************************************************************************
     * Compares to CountDownTimer objects and returns an int 1, 0, or -1 based on whether the first
     * object (t1) is greater than, equal to, or less than the second object (t2)
     * @param t1 first object being compared
     * @param t2 second object being compared
     * @return
     ***************************************************************************************************/
    public static int compareTo(CountDownTimer t1, CountDownTimer t2) {
        if (t1.convertToSeconds() > t2.convertToSeconds())
            return 1;
        else if (t1.convertToSeconds() < t2.convertToSeconds())
            return -1;
        return 0;
    }

    /***************************************************************
     * subtracts the input amount of seconds from a CountDownTimer
     * @param seconds amount of seconds the user wants to subtract
     ***************************************************************/
    public void subtract(int seconds) {
        // places the amount of seconds into an integer
        int tempSeconds = this.convertToSeconds();
        // subtracts the input seconds from the seconds that were converted
        tempSeconds -= seconds;
        // converts the new seconds back into the object
        formatSeconds(tempSeconds);
    }


    /*******************************************************************************************
     * Subtracts the amount of time contained in one CountDownTimer from another CountDownTimer
     * @param other CountDownTimer that is doing the subtracting
     *******************************************************************************************/
    public void subtract(CountDownTimer other) {
        int otherSeconds = other.convertToSeconds();
        this.subtract(otherSeconds);
    }

    /***********************************************************************
     * Adds seconds to the object based on what is put into the parameter
     * @param seconds amount of seconds being added to the CountDownTimer
     ************************************************************************/
    public void add(int seconds) {
        // keeps the method from adding when the toggle is activated
        if (toggle == false) {
            int tempSeconds = this.convertToSeconds();
            tempSeconds += seconds;
            formatSeconds(tempSeconds);
        } else
            throw new IllegalArgumentException(
                    "Cannot use add when toggle is enabled");
    }
/**
 * Adds the seconds from one CountDownTimer to another CountDownTimer
 * @param other CountDownTimer that is being added to another CountDowntimer
 */
    public void add(CountDownTimer other) {
        // doesn't allow the method to add when the toggle is true
        if (toggle == false) {
            int otherSeconds = other.convertToSeconds();
            this.add(otherSeconds);
        } else
            throw new IllegalArgumentException(
                    "Cannot use add when toggle is enabled");
    }

    /*******************************************
     * Decreases the CountDownTimer by 1 second
     *******************************************/
    public void dec() {
        int tempSeconds = this.convertToSeconds();
        tempSeconds--;
        formatSeconds(tempSeconds);
    }

    /****************************************************
     * Increases the CountDownTimer object by 1 second
     ***************************************************/
    public void inc() {
        int tempSeconds = this.convertToSeconds();
        tempSeconds--;
        formatSeconds(tempSeconds);
    }

    /**
     * Returns the object as a string in the format of "00:00:00"
     */
    public String toString() {
        String time = "" + this.hours + ":";
        if (this.minutes < 10) {
            time += "0" + this.minutes + ":";
        } else {
            time += this.minutes + ":";
        }
        if (this.seconds < 10) {
            time += "0" + this.seconds;
        } else {
            time += this.seconds;
        }
        return time;
    }

    /************************************************
     * Saves the object with a specified name
     * @param fileName name of the file being saved
     *************************************************/
    public void save(String fileName) {
        PrintWriter out = null;
        try {
            out = new PrintWriter(new BufferedWriter(new FileWriter(fileName)));
        } catch (IOException e) {
            e.printStackTrace();
        }
        out.println(this.hours);
        out.println(this.minutes);
        out.println(this.seconds);
        out.close();
    }
/**************************************************
 * Loads the object with the specified name
 * @param fileName Name of the file being loaded
 **************************************************/
    public void load(String fileName) {
        try {
            Scanner fileReader = new Scanner(new File(fileName));

            this.hours = fileReader.nextInt();
            this.minutes = fileReader.nextInt();
            this.seconds = fileReader.nextInt();

            fileReader.close();
            System.out.println("Hours: " + this.hours);
            System.out.println("Minutes: " + this.minutes);
            System.out.println("Seconds: " + this.seconds);
        } catch (FileNotFoundException error) {
            System.out.println("File not found");
        } catch (IOException error) {
            System.out.println("OH NO THAT WAS NOT SUPPOSED TO HAPPEN");
        }
    }
/**********************************************************************************************
 * Switches the toggle boolean, and doesn't allow the add methods to work when it is activated
 ************************************************************************************************/
    public static void toggleSuspend() {
        if (toggle == false)
            toggle = true;
        if (toggle == true)
            toggle = false;
    }

    /***********************************************************************************
     * Formats a certain amount of seconds and puts it into an existing CountDownTimer
     * @param seconds seconds being formatted
     ***********************************************************************************/
    private void formatSeconds(int seconds) {
        this.hours = seconds / 3600;
        seconds %= 3600;
        this.minutes = seconds / 60;
        this.seconds = seconds % 60;
    }

    /*****************************************************************************
     * Returns the amount of seconds that are contained in a CountDownTime object
     *****************************************************************************/
    private int convertToSeconds() {
        int hSeconds = hours * 3600;
        int mSeconds = minutes * 60;
        return hSeconds + mSeconds + seconds;
    }
}

这是我的GUI面板类,我在哪里我遇到了问题。我正在使用数组来制作多个计时器。

And here is my GUI panel class, where I'm having my problem. I'm using arrays to make multiple timers.

package pack1;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;

public class MyTimerPanel extends JPanel {
    /** Array of CountDownTimers that will be used */
    private CountDownTimer[] cdt;

    /** Array of Timer objects that are used to count down by 1 every second*/
    private Timer[] javaTimer;
    /** Array of TimerListeners that are called in the Timer objects */
    private TimerListener timer[];

    /** Array of JPanels that will hold each timer interface */
    private JPanel[] panel;
    /** Array of JLabels for the display of time, seconds, minutes, and hours */
    private JLabel[] timeDisplay, secDisplay, minDisplay, hourDisplay;
    /** Array of JButtons that start, stop, and set the timer */
    private JButton[] start, stop, set;
    /** Array of JTextFields that the user will input the seconds, minutes, and hours*/
    private JTextField[] sec, min, hour;

    /** Array of booleans that will determine if the timer should be counting down */ 
    private boolean[] go;

    /** Amount of milliseconds the timer needs to wait before performing an action */
    private final int DELAY = 1000;

    /** Amount of CountDownTimers in the interfaces */ 
    private final int AMOUNT = 3;

    // test integer
    int[] count;


    /******************************************************************************************
     * Constructor that sets the lengths of the arrays and instantiates each part of the array
     ******************************************************************************************/
    public MyTimerPanel() {
        count = new int[AMOUNT];
        timer = new TimerListener[AMOUNT];
        cdt = new CountDownTimer[AMOUNT];
        javaTimer = new Timer[AMOUNT];
        panel = new JPanel[AMOUNT];
        timeDisplay = new JLabel[AMOUNT];
        secDisplay = new JLabel[AMOUNT];
        minDisplay = new JLabel[AMOUNT];
        hourDisplay = new JLabel[AMOUNT];
        sec = new JTextField[AMOUNT];
        min = new JTextField[AMOUNT];
        hour = new JTextField[AMOUNT];
        start = new JButton[AMOUNT];
        stop = new JButton[AMOUNT];
        set = new JButton[AMOUNT];
        go = new boolean[AMOUNT];
        // Defines each part of each array and adds the neccessary components to the buttons and panels
        for (int i = 0; i < AMOUNT; i++) {
            count[i] = 0;
            cdt[i] = new CountDownTimer(0, 0, 0);
            go[i] = false;
            timer[i] = new TimerListener();
            javaTimer[i] = new Timer(DELAY, timer[i]);
            javaTimer[i].start();
            timeDisplay[i] = new JLabel(cdt[i].toString());
            secDisplay[i] = new JLabel("Seconds: ");
            minDisplay[i] = new JLabel("Minutes: ");
            hourDisplay[i] = new JLabel("Hours: ");
            sec[i] = new JTextField(5);
            min[i] = new JTextField(5);
            hour[i] = new JTextField(5);
            start[i] = new JButton("Start");
            stop[i] = new JButton("Stop");
            set[i] = new JButton("Set");
            start[i].addActionListener(timer[i]);
            stop[i].addActionListener(timer[i]);
            set[i].addActionListener(timer[i]);
            panel[i] = new JPanel();
            panel[i].add(hourDisplay[i]);
            panel[i].add(hour[i]);
            panel[i].add(minDisplay[i]);
            panel[i].add(min[i]);
            panel[i].add(secDisplay[i]);
            panel[i].add(sec[i]);
            panel[i].add(start[i]);
            panel[i].add(stop[i]);
            panel[i].add(set[i]);
            panel[i].add(timeDisplay[i]);
            add(panel[i]);
        }
        setPreferredSize(new Dimension(750, 40 * AMOUNT));
    }

    /*******************************************************************
     * Action Listener that activates when certain buttons are pressed
     *******************************************************************/
    private class TimerListener implements ActionListener {
        /********************************************************************
         * ActionListener that is activated whenever someone pushes a button
         ********************************************************************/
        public void actionPerformed(ActionEvent e) {
            // CountDownTimer that will be compared to at zero
            CountDownTimer zero = new CountDownTimer();
            // placeholders for the text from the JTextFields
            String[] secText = new String[AMOUNT];
            String[] minText = new String[AMOUNT];
            String[] hourText = new String[AMOUNT];
            // runs through each part of the arrays and checks which button needs to be pressed
            for (int i = 0; i < AMOUNT; i++) {
                // checks if one of the start buttons is being pressed
                if (e.getSource() == start[i]){
                    go[i] = true;
                }
                // checks if one of the stop buttons is being pressed
                else if (e.getSource() == stop[i])
                    go[i] = false;
                // checks if one of the set buttons is being pressed and sets the minutes hours and seconds input
                if (e.getSource() == set[i]) {
                    secText[i] = sec[i].getText();
                    minText[i] = min[i].getText();
                    hourText[i] = hour[i].getText();
                    // if one of the boxes is blank, it will input zero
                    if (secText[i].equals("")) {
                        cdt[i].seconds = 0;
                    } else {
                        cdt[i].seconds = Integer.parseInt(secText[i]);
                    }
                    if (minText[i].equals("")) {
                        cdt[i].minutes = 0;
                    } else {
                        cdt[i].minutes = Integer.parseInt(minText[i]);
                    }
                    if (hourText[i].equals("")) {
                        cdt[i].hours = 0;
                    } else {
                        cdt[i].hours = Integer.parseInt(hourText[i]);
                    }
                    // sets timeDisplay to show the time in the countdowntimer
                    timeDisplay[i].setText(cdt[i].toString());
                    // stops the timer after setting it
                    go[i] = false;
                }
                // the timer should be counting down if the go boolean is true or the countdowntimer isn't zero
                if (go[i] == true && !cdt[i].equals(zero)) {
                    javaTimer[i].start();
                    cdt[i].dec();
                    timeDisplay[i].setText(cdt[i].toString());
                    count[i]++;
                    }
                // the timer shouldn't be counting down if the go boolean is false or the countdowntimer is zero
                if (go[i] == false || cdt[i].compareTo(zero) <= 0) {
                    javaTimer[i].stop();
                }
            }
            // for testing purposes
            System.out.println(count[0] + "\t" + count[1] + "\t" + count[2]);

        }
    }
}


推荐答案

问题在于您的 TimerListener

基本上,正在发生的事情是它被调用的时间,它执行这个代码块......

Basically, what's happening, is each time it is called, it executes this code block...

if (go[i] == true && !cdt[i].equals(zero)) {
    javaTimer[i].start();
    cdt[i].dec();
    timeDisplay[i].setText(cdt[i].toString());
    count[i]++;
}

这意味着,如果你有3个计数器在运行,那么这个代码块将被执行每秒9次。每个计数器三次/ 计时器

This means, if you have 3 counters running, this code block will be executed 9 times per second. Three times per counter/Timer

TimerListener 是过于笼统,并试图做太多事情。

You TimerListener is too generalised and is trying to do too many things.

或者,创建一个单一计时器定期基础并根据需要更新每个计数器(以便每个循环处理单个计数器)或修改您的 TimerListener ,以便它获取有关它正在管理的计数器的详细信息仅与该计数器进行交易。

Either, create a "single" Timer that ticks on a regular bases and updates each counter as required (so that each loop is dealing with a single counter) OR modify your TimerListener so that it takes details about the counter it is managing and deals ONLY with that counter.

更新可能的解决方案

此示例使用一个集中的计时器,它只是在后台打勾。根据需要,在计时器中注册一个特殊的计数器,然后在时通知它勾选计数器然后递减 CountDownTimer 并更新UI。

This example uses a single, centralised Timer which simply ticks away in the background. As required, a special Counter is registered with the Timer, which then notifies it when a tick occurs. The Counter then decrements the CountDownTimer and updates the UI.

这是一个不完美的例子,因为我希望 CountDownTimer 有一个监听器接口能够通知已注册的监听器对象的状态已经以某种方式发生了变化。这可以通过包装 Counter 类来实现,但我很懒。

This is an imperfect example, as I would prefer that the CountDownTimer had a listener interface capable of notifying registered listeners that object's state has changed in some way. This could be achieved through the wrapper Counter class, but I'm to lazy.

import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Scanner;
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.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestTimerPane {

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

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

                CountDownManager countDownManager = new CountDownManager();

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new GridBagLayout());
                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridwidth = GridBagConstraints.REMAINDER;
                frame.add(new TimerPane(countDownManager), gbc);
                frame.add(new TimerPane(countDownManager), gbc);
                frame.add(new TimerPane(countDownManager), gbc);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class CountDownManager {

        private List<Counter> timers;

        public CountDownManager() {
            timers = new ArrayList<>(25);

            Timer timer = new Timer(1000, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Iterator<Counter> it = timers.iterator();
                    while (it.hasNext()) {
                        it.next().tick(CountDownManager.this);
                    }
                }
            });
            timer.start();
        }

        public void add(Counter timer) {
            timers.add(timer);
        }

        public void remove(Counter timer) {
            timers.remove(timer);
        }

    }

    public class TimerPane extends JPanel {

        private JTextField fldHours;
        private JTextField fldMins;
        private JTextField fldSecs;

        private JButton btnStart;
        private JButton btnStop;
        private JButton btnSet;

        private JLabel countDown;

        private CountDownTimer countDownTimer;

        private Counter counter;

        public TimerPane(final CountDownManager countDownManager) {
            fldHours = new JTextField(2);
            fldMins = new JTextField(2);
            fldSecs = new JTextField(2);

            btnSet = new JButton("Set");
            btnStop = new JButton("Stop");
            btnStart = new JButton("Start");

            countDown = new JLabel("??:??:??");

            add(fldHours);
            add(new JLabel(":"));
            add(fldMins);
            add(new JLabel(":"));
            add(fldSecs);
            add(btnSet);
            add(btnStart);
            add(btnStop);
            add(countDown);

            btnSet.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    countDownTimer = new CountDownTimer(
                            toInt(fldHours),
                            toInt(fldMins),
                            toInt(fldSecs));
                    counter = new Counter(countDown, countDownTimer);
                    countDown.setText(countDownTimer.toString());
                }
            });

            btnStart.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (counter != null) {
                        countDownManager.add(counter);
                    }
                }
            });
            btnStop.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (counter != null) {
                        countDownManager.remove(counter);
                    }
                }
            });
        }

        protected int toInt(JTextField field) {
            int value = 0;
            try {
                value = Integer.parseInt(field.getText());
            } catch (NumberFormatException exp) {
            }
            return value;
        }

    }

    public class Counter {

        private JLabel output;
        private CountDownTimer timer;

        public Counter(JLabel output, CountDownTimer timer) {
            this.output = output;
            this.timer = timer;
        }

        public void tick(CountDownManager manager) {
            timer.dec();
            output.setText(timer.toString());
            if (timer.convertToSeconds() <= 0) {
                manager.remove(this);
            }
        }

    }

    public static class CountDownTimer {

        /**
         * Amount of hours that are being counted down in the timer
         */
        int hours;
        /**
         * Amount of minutes that are being counted down in the timer
         */
        int minutes;
        /**
         * Amount of seconds that are being counted down in the timer
         */
        int seconds;

        /**
         * Boolean that determines if the add method will work. It is changed with
         * the toggleSuspend method
         */
        static boolean toggle = false;

        /**
         * ***************************************************************************************
         * Default constructor that creates a CountDownTimer object with no time
         * contained in it
         * ***************************************************************************************
         */
        public CountDownTimer() {
            hours = 0;
            minutes = 0;
            seconds = 0;
        }

        /**
         * *******************************************************************************************
         * Constructor that uses the input amount of hours, minutes, and seconds to
         * count down from
         *
         * Does not allow time that is negative or allow seconds or minutes that are
         * over 60
         *
         * @param hours amount of hours that will be counted down from
         * @param minutes amount of minutes that will be counted down from
         * @param seconds amount of seconds that will be counted down from
         * *******************************************************************************************
         */
        public CountDownTimer(int hours, int minutes, int seconds) {
            super();

            // doesn't allow negative minutes, seconds, or hours
            if (seconds < 0 || minutes < 0 || hours < 0) {
                throw new IllegalArgumentException("Time cannot be negative");
            }
            // doesn't allow seconds that are higher than 60
            if (seconds >= 60) {
                throw new IllegalArgumentException(
                        "Cannot have more than 60 seconds");
            }
            // doesn't allow minutes that are higher than 60
            if (minutes >= 60) {
                throw new IllegalArgumentException(
                        "Cannot have more than 60 minutes");
            }
            this.hours = hours;
            this.minutes = minutes;
            this.seconds = seconds;
        }

        /**
         * *******************************************************************
         * Constructor that takes minutes and seconds, and sets hours to zero also
         * doesn't allow minutes or seconds to be negative or above 60
         *
         * @param minutes amount of minutes that will be counted down from
         * @param seconds amount of seconds that will be counted down from
         * ***********************************************************************
         */
        public CountDownTimer(int minutes, int seconds) {
            super();
            // doesn't allow seconds minutes or hours to be negative
            if (seconds < 0 || minutes < 0 || hours < 0) {
                throw new IllegalArgumentException("Time cannot be negative");
            }
            // doesn't allow seconds to be greater than 60
            if (seconds >= 60) {
                throw new IllegalArgumentException(
                        "Cannot have more than 60 seconds");
            }
            // doesn't allow minutes to be greater than 60
            if (minutes >= 60) {
                throw new IllegalArgumentException(
                        "Cannot have more than 60 minutes");
            }

            this.hours = 0;
            this.minutes = minutes;
            this.seconds = seconds;
        }

        /**
         * *********************************************************************
         * Constructor that only takes seconds and sets hours and minutes to 0 does
         * not allow the seconds to be above 60 or negative
         *
         * @param seconds amount of seconds that will be counted down from
         * ***********************************************************************
         */
        public CountDownTimer(int seconds) {
            super();

            // doesn't allow seconds minutes or hours to be negative
            if (seconds < 0 || minutes < 0 || hours < 0) {
                throw new IllegalArgumentException("Time cannot be negative");
            }
            // doesn't allow seconds to be greater than 60
            if (seconds >= 60) {
                throw new IllegalArgumentException(
                        "Cannot have more than 60 seconds");
            }
            this.hours = 0;
            this.minutes = 0;
            this.seconds = seconds;
        }

        /**
         * Constructor that clones one CountDownTimer object into a new
         * CountDownTimer object
         *
         * @param other The CountDownTimer object that is being cloned
         *
         */
        public CountDownTimer(CountDownTimer other) {
            this.hours = other.hours;
            this.minutes = other.minutes;
            this.seconds = other.seconds;
        }

        /**
         * *****************************************************************************************************************************
         * Constructor that converts a string in the format of "00:00:00" into
         * seconds minutes and hours so it can be counted down from
         *
         * @param startTime String that is converted into seconds minutes and hours
         * *****************************************************************************************************************************
         */
        public CountDownTimer(String startTime) {
            // Separates the seconds minutes and hours into an array
            String[] parts = startTime.split(":");
            // if the array has only one cell, that means only seconds were input
            if (parts.length == 1) {
                seconds = Integer.parseInt(parts[0]);
            }
            // if the array has only 2 cells that means there is only minutes and seconds input
            if (parts.length == 2) {
                minutes = Integer.parseInt(parts[0]);
                seconds = Integer.parseInt(parts[1]);
            }
            // if the array has 3 cells that means there is seconds minutes and hours input
            if (parts.length == 3) {
                hours = Integer.parseInt(parts[0]);
                minutes = Integer.parseInt(parts[1]);
                seconds = Integer.parseInt(parts[2]);
            }
            // doesn't allow seconds minutes or hours to be negative
            if (seconds < 0 || minutes < 0 || hours < 0) {
                throw new IllegalArgumentException("Time cannot be negative");
            }
            // doesn't allow seconds to be greater than or equal to 60
            if (seconds >= 60) {
                throw new IllegalArgumentException(
                        "Cannot have more than 60 seconds");
            }
            // doesn't allow minutes to be greater than or equal to 60
            if (minutes >= 60) {
                throw new IllegalArgumentException(
                        "Cannot have more than 60 minutes");
            }
        }

        /**
         * ************************************************************************************************
         * Method that returns true or false based on whether or not two
         * CountDownTimer objects are equal
         *
         * @param other Object that is being compared to another CountDownTimer
         * ************************************************************************************************
         */
        public boolean equals(Object other) {
            // converts the two objects to seconds then compares them
            if (this.convertToSeconds() == ((CountDownTimer) other)
                    .convertToSeconds()) {
                return true;
            }
            return false;
        }

        /**
         * ******************************************************************************
         * Returns a boolean based on whether two CountDownTimers, t1 and t2, are
         * equal
         *
         * @param t1 first CountDownTimer being compared
         * @param t2 second CountDownTimer being compared
         * ******************************************************************************
         */
        public static boolean equals(CountDownTimer t1, CountDownTimer t2) {
            // converts the two objects to seconds and then compares them
            if (t1.convertToSeconds() == t2.convertToSeconds()) {
                return true;
            }
            return false;
        }

        /**
         * **********************************************************************************************
         * Compares to CountDownTimer objects and returns an int 1, 0, or -1 based
         * on whether the first object is greater than, equal to, or less than the
         * CountDownTimer in the parameter
         *
         * @param other CountDownTimer that is being compared
         * ***********************************************************************************************
         */
        public int compareTo(CountDownTimer other) {
            if (this.convertToSeconds() > other.convertToSeconds()) {
                return 1;
            } else if (this.convertToSeconds() < other.convertToSeconds()) {
                return -1;
            }
            return 0;
        }

        /**
         * ************************************************************************************************
         * Compares to CountDownTimer objects and returns an int 1, 0, or -1 based
         * on whether the first object (t1) is greater than, equal to, or less than
         * the second object (t2)
         *
         * @param t1 first object being compared
         * @param t2 second object being compared
         * @return
         * *************************************************************************************************
         */
        public static int compareTo(CountDownTimer t1, CountDownTimer t2) {
            if (t1.convertToSeconds() > t2.convertToSeconds()) {
                return 1;
            } else if (t1.convertToSeconds() < t2.convertToSeconds()) {
                return -1;
            }
            return 0;
        }

        /**
         * *************************************************************
         * subtracts the input amount of seconds from a CountDownTimer
         *
         * @param seconds amount of seconds the user wants to subtract
         * *************************************************************
         */
        public void subtract(int seconds) {
            // places the amount of seconds into an integer
            int tempSeconds = this.convertToSeconds();
            // subtracts the input seconds from the seconds that were converted
            tempSeconds -= seconds;
            // converts the new seconds back into the object
            formatSeconds(tempSeconds);
        }

        /**
         * *****************************************************************************************
         * Subtracts the amount of time contained in one CountDownTimer from another
         * CountDownTimer
         *
         * @param other CountDownTimer that is doing the subtracting
         * *****************************************************************************************
         */
        public void subtract(CountDownTimer other) {
            int otherSeconds = other.convertToSeconds();
            this.subtract(otherSeconds);
        }

        /**
         * *********************************************************************
         * Adds seconds to the object based on what is put into the parameter
         *
         * @param seconds amount of seconds being added to the CountDownTimer
         * **********************************************************************
         */
        public void add(int seconds) {
            // keeps the method from adding when the toggle is activated
            if (toggle == false) {
                int tempSeconds = this.convertToSeconds();
                tempSeconds += seconds;
                formatSeconds(tempSeconds);
            } else {
                throw new IllegalArgumentException(
                        "Cannot use add when toggle is enabled");
            }
        }

        /**
         * Adds the seconds from one CountDownTimer to another CountDownTimer
         *
         * @param other CountDownTimer that is being added to another CountDowntimer
         */
        public void add(CountDownTimer other) {
            // doesn't allow the method to add when the toggle is true
            if (toggle == false) {
                int otherSeconds = other.convertToSeconds();
                this.add(otherSeconds);
            } else {
                throw new IllegalArgumentException(
                        "Cannot use add when toggle is enabled");
            }
        }

        /**
         * *****************************************
         * Decreases the CountDownTimer by 1 second
         * *****************************************
         */
        public void dec() {
            int tempSeconds = this.convertToSeconds();
            tempSeconds--;
            formatSeconds(tempSeconds);
        }

        /**
         * **************************************************
         * Increases the CountDownTimer object by 1 second
         * *************************************************
         */
        public void inc() {
            int tempSeconds = this.convertToSeconds();
            tempSeconds--;
            formatSeconds(tempSeconds);
        }

        /**
         * Returns the object as a string in the format of "00:00:00"
         */
        public String toString() {
            String time = "" + this.hours + ":";
            if (this.minutes < 10) {
                time += "0" + this.minutes + ":";
            } else {
                time += this.minutes + ":";
            }
            if (this.seconds < 10) {
                time += "0" + this.seconds;
            } else {
                time += this.seconds;
            }
            return time;
        }

        /**
         * **********************************************
         * Saves the object with a specified name
         *
         * @param fileName name of the file being saved
         * ***********************************************
         */
        public void save(String fileName) {
            PrintWriter out = null;
            try {
                out = new PrintWriter(new BufferedWriter(new FileWriter(fileName)));
            } catch (IOException e) {
                e.printStackTrace();
            }
            out.println(this.hours);
            out.println(this.minutes);
            out.println(this.seconds);
            out.close();
        }

        /**
         * ************************************************
         * Loads the object with the specified name
         *
         * @param fileName Name of the file being loaded
         * ************************************************
         */
        public void load(String fileName) {
            try {
                Scanner fileReader = new Scanner(new File(fileName));

                this.hours = fileReader.nextInt();
                this.minutes = fileReader.nextInt();
                this.seconds = fileReader.nextInt();

                fileReader.close();
                System.out.println("Hours: " + this.hours);
                System.out.println("Minutes: " + this.minutes);
                System.out.println("Seconds: " + this.seconds);
            } catch (FileNotFoundException error) {
                System.out.println("File not found");
            } catch (IOException error) {
                System.out.println("OH NO THAT WAS NOT SUPPOSED TO HAPPEN");
            }
        }

        /**
         * ********************************************************************************************
         * Switches the toggle boolean, and doesn't allow the add methods to work
         * when it is activated
         * **********************************************************************************************
         */
        public static void toggleSuspend() {
            if (toggle == false) {
                toggle = true;
            }
            if (toggle == true) {
                toggle = false;
            }
        }

        /**
         * *********************************************************************************
         * Formats a certain amount of seconds and puts it into an existing
         * CountDownTimer
         *
         * @param seconds seconds being formatted
         * *********************************************************************************
         */
        private void formatSeconds(int seconds) {
            this.hours = seconds / 3600;
            seconds %= 3600;
            this.minutes = seconds / 60;
            this.seconds = seconds % 60;
        }

        /**
         * ***************************************************************************
         * Returns the amount of seconds that are contained in a CountDownTime
         * object
         * ***************************************************************************
         */
        private int convertToSeconds() {
            int hSeconds = hours * 3600;
            int mSeconds = minutes * 60;
            return hSeconds + mSeconds + seconds;
        }
    }

}

Now, if you need a separate Timer per CountDownTimer, then I would probably create some kind of \"worker\" class that would take a CountDownTimer and that had a self contained Timer. I would also provide some kind of listener that interested parties could register to and would allow them to update the UI as they see fit...

Now, if you need a separate Timer per CountDownTimer, then I would probably create some kind of "worker" class that would take a CountDownTimer and that had a self contained Timer. I would also provide some kind of listener that interested parties could register to and would allow them to update the UI as they see fit...

这篇关于多个Swing计时器导致多个动作发生的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆