1

What I am trying to do:

I am trying to make a basic timer in java.

What approach I am following:

I am using Thread.sleep(1000) to make the main thread sleep for 1 second and as soon the Thread awakes the seconds field in the code increments by 1 and there is normal mathematics for minutes and hours.

The code itself:

public class a extends javax.swing.JFrame {

    javax.swing.JTextField text,minute,starter,hours;

    a() {
        super("Timer!");

        try{ 
            javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName()); 
        } catch(Exception e) {

        } finally { 

            this.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER,20,20));    

            text = new javax.swing.JTextField();
            hours = new javax.swing.JTextField();
            hours.setPreferredSize(new java.awt.Dimension(25,25));
            this.add(hours);

            minute = new javax.swing.JTextField();
            minute.setPreferredSize(new java.awt.Dimension(25,25));

            javax.swing.JButton starter = new javax.swing.JButton("Start!");
            this.add(minute);

            text.setPreferredSize(new java.awt.Dimension(25,25));
            this.add(text);   

            starter.addMouseListener(new java.awt.event.MouseAdapter() {

                @Override
                public void mouseReleased(java.awt.event.MouseEvent e) {
                    timer();
                }

            });

            this.add(starter);
            this.pack();
            this.setLocationRelativeTo(null);
            this.setVisible(true);
            text.setEditable(false);

            text.setText("0");
            minute.setEditable(false);
            hours.setEditable(false);    
            minute.setText("0");                      
            hours.setText("0");

        }
    }

    private void timer() {

        while(true) {

            try {    

                Thread.sleep(1000);

                int i = Integer.parseInt(text.getText());
                i++;
                text.setText(String.valueOf(i%60));

                if(i==60) {

                    i = Integer.parseInt(minute.getText());
                    i++;      
                    minute.setText(String.valueOf(i));

                    if(i==60) {

                        minute.setText("0");
                        int number = Integer.parseInt(hours.getText());
                        hours.setText(String.valueOf(++number));

                    }                             
                }
            } catch(Exception e) {
                text.setText("crap!");
            }
        }   
    }

    public static void main(String args[]){
        a o = new a();
    }

}

My Problem

My problem or question is that when I had not used the JButton starter and was just calling the timer() method inside the constructor, the timer worked like a charm, but when I am using the JButton and have put the timer() call in its event listener to start the timer as per requirement the application just freezes and nothing happens.

Like I mentioned above, if I just call timer inside the constructor and remove the JButton from the application everything works fine. But when using the JButton (in order to manually start the timer), the app just freezes.

Edit:

I am sorry! I forgot to mention when the app freezes it freezes upon clicking the JButton.

Edit:

This question is not a duplicate of the other question as the question is about how to create a timer in java, I never asked for that! I know that, What I asked in my question was what mistake I am making in my code, which one of the answers explains very well. I never asked the question "how to create timer in java".

iRaySpace
  • 65
  • 8
Kaushal Jain
  • 139
  • 1
  • 11
  • You are not supposed to do any lengthy operation within an event handler. `sleep()` is a lengthy operation. Use `javax.swing.Timer`. – RealSkeptic Apr 26 '15 at 06:54
  • 1
    In the future, please make your title more specific, so others don't have to actually open the post to get an idea of the problem – Vince Apr 26 '15 at 07:00
  • @VinceEmigh, I will definitely keep that in mind from next time. – Kaushal Jain Apr 26 '15 at 07:03
  • You might want to read [How do I ask a good question](http://stackoverflow.com/help/how-to-ask), which enhances the probability for getting a useful answer _drastically_. You might find [ESR](https://en.m.wikipedia.org/wiki/Eric_S._Raymond)'s excellent essay [How To Ask Questions The Smart Way](http://catb.org/~esr/faqs/smart-questions.html) helpful, too. ;) – Markus W Mahlberg Apr 26 '15 at 08:47
  • You can also use `@Scheduled` if you have used Spring for DI. – Roman C Apr 26 '15 at 09:47

2 Answers2

4

You're not calling sleep() in the main thread. You're doing it in the event dispatch thread. This thread is the one handling all the UI events and repainting the UI components when needed. Since you're forcing it to sleep forever, it can't do this job anymore.

Use a javax.swing.Timer.

Note that it works by accident when the timer is in the constructor: you're calling the constructor from the main thread, and are thus not blocking the EDT. But that also violates the swing threading rules: swing components must always be created and accessed from the EDT. Read the tutorial about concurrency in swing.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
1

you approach is completely wrong. If you freeze the gui inside the button routine, in the way you did it, the control never returns and it doesn't allows you to do anything. the button routine is trying to update the gui not from the "main loop" (The "main loop" also manages the gui aspect), for this reason it needs free time in the thread to do it, but you call again sleep so the gui never has the time to update itself.

The correct approach for any software, where possible, is to never freeze the gui. Use asynctask or new thread Or timertask to measure the time passing and Then periodically update the gui. You will then use your button just to start your asynctask or the new thread. It's full the internet of samples for this.

This is an example, try it and let me know:

 import java.util.Timer;


 Timer timer = new Timer();

 timer.scheduleAtFixedRate(new TimerTask() {
   @Override
   public void run() {
     // Your code here
   }
   }, 1000, 1000);
Gaucho
  • 1,328
  • 1
  • 17
  • 32