Search code examples
javaswinguser-interfacejavax.swing.timer

Timer creates a new Window on Start


My timer is creating a new window with non-working buttons when I hit the start button. The change in display only happens in the new window but the start/stop functionality only works in the old window. I'm not sure what's going on here. Can someone help me figure out how to stop it from creating a new window when start is pressed?

I have three classes I'm working with. The first runs the timer.

package timer;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
import java.awt.event.*;

public class TaskTimer extends TaskTimerWindow {

    int seconds = 0;
    int minutes = 0;
    int hours = 0;
    final int UNIT = 1000;
    boolean stopped = false;
    Timer timer;

    public TaskTimer() {

        ActionListener go = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                count();    
            }   
        };

        timer = new Timer(UNIT, go);
        timer.start();      
    }

    public void resume() {
        if(stopped) {
            seconds = 0;
            minutes = 0;
            hours = 0;
        }   
    }

    public void end() {
        timer.stop();   
    }

    public void count() {
        if(seconds < 59) {
            seconds++;
        } else if(minutes < 59) {
            seconds = 0;
            minutes++;
        } else {
            seconds = 0;
            minutes = 0;
            hours++;
        }
        changeDisplay(String.format("%02d", hours) + ":" 
             + String.format("%02d", minutes)  + ":" 
             + String.format("%02d", seconds));
    }
}

The second creates and updates the display.

package timer;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;


public class TaskTimerWindow extends JFrame {

    JLabel timeDisplay;
    JButton start, stop, pause;

    public TaskTimerWindow() {

        JPanel timerWindow = new JPanel();
        JPanel buttonSpace = new JPanel();

        timeDisplay = new JLabel("00:00:00");
        timeDisplay.setHorizontalAlignment((int) CENTER_ALIGNMENT); 
        timeDisplay.setFont(new Font("Arial", Font.PLAIN, 48));

        timeDisplay.setBackground(Color.WHITE);

        timerWindow.add(timeDisplay);

        start = new JButton("Start");
        stop = new JButton("Stop");
        pause = new JButton("Pause");

        buttonSpace.add(start);
        buttonSpace.add(stop);
        buttonSpace.add(pause);

        getContentPane().add(timerWindow, BorderLayout.NORTH);
        getContentPane().add(buttonSpace);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
        setLocationRelativeTo(null);
        setTitle("Task Timer");
        pack();
    }

    public JLabel getText() {
        return timeDisplay;
    }

    public void changeDisplay(String time) {
        getText().setText(time);
    }

}

And the third is the controller.

package timer;

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

public class ControlTimer {
    boolean stopped = false;
    boolean paused = false;
    TaskTimer timer;


    public ControlTimer() {
        TaskTimerWindow window = new TaskTimerWindow();
        window.start.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                timer = new TaskTimer();
            }
        });

        window.stop.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                stopped = true;
                timer.end();
            }
        });

        window.pause.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                paused = true;
            }
        });
    }
}

Solution

  • So the main problem is in your ControlTimer class. As TaskTimer extends TaskTimerWindow it was creating new window each time start button was pressed. You should modify it like following:

    public class ControlTimer {
        boolean stopped = false;
        boolean paused = false;
        TaskTimer timer;
    
    
        public ControlTimer() {
            timer = new TaskTimer();
            timer.start.addActionListener(new ActionListener() {
    
                public void actionPerformed(ActionEvent e) {
                    timer.resume();
                    timer.start();
                }
            });
    
            timer.stop.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    timer.stopped = true;
                    timer.end();
                }
            });
    
            timer.pause.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    timer.end();
                }
            });
        }
    }
    

    Also there're some minor changes in TaskTimer class (removing timer.start() from constructor and introducing separate start() method instead:

    public TaskTimer() {
    
        ActionListener go = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                count();
            }
        };
    
        timer = new Timer(UNIT, go);
    }
    
    public void start() {
        timer.start();
    }