0

I'm trying to make a timer application in Java but during the counting process, it won't execute main (also opening the window) until the counter finishes. This is what I mean:

long timeElapsed = 0;
    long timeStart = System.currentTimeMillis();
    for (long counter=0;counter<5;++counter) {
        TimeUnit.SECONDS.sleep(1);
        timeElapsed = (System.currentTimeMillis() - timeStart)/1000;
        display.setText(Long.toString(timeElapsed));
    }
    String myString = Long.toString(timeElapsed);

The program won't make a window until the for statement is finished which is bad because it doesnt display the time until its done which is not what im aiming for. Is there any way to window update while it is running so that the program displays the time elapsed?

My code:

import java.awt.EventQueue;
import javax.swing.JFrame;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.util.concurrent.TimeUnit;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JButton;

public class TimerGUI {

    private JFrame frame;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    TimerGUI window = new TimerGUI();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the application.
     * @throws InterruptedException 
     */
    public TimerGUI() throws InterruptedException {
        initialize();
    }

    /**
     * Initialize the contents of the frame.
     * @throws InterruptedException 
     */
    private void initialize() throws InterruptedException {
        JLabel display = new JLabel("a");
        // TIME
        long timeElapsed = 0;
        long timeStart = System.currentTimeMillis();
        for (long counter=0;counter<5;++counter) {
            TimeUnit.SECONDS.sleep(1);
            timeElapsed = (System.currentTimeMillis() - timeStart)/1000;
            display.setText(Long.toString(timeElapsed));
        }
        String myString = Long.toString(timeElapsed);


        //WINDOW
        frame = new JFrame();
        frame.setBounds(100, 100, 450, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(null);

        // LABEL
        //display = new JLabel(myString);
        display.setBounds(165, 64, 89, 54);
        frame.getContentPane().add(display);


        //BUTTON
        JButton btnNewButton = new JButton("New button");
        btnNewButton.setBounds(165, 169, 89, 32);
        frame.getContentPane().add(btnNewButton);



    }
}

Note: Im not using the Button part of program yet and also the code Im trying to fix is in the method Initialize().

DudeManGuy
  • 123
  • 2
  • 12

2 Answers2

2

Welcome to the wonderful world of "Honey, I blocked the Event Dispatching Thread"

Swing is both single thread and not thread safe. This means, if you block the Event Dispatching Thread, by doing something like Thread.sleep, then the UI will not be able to update, because you've blocked the thread responsible for updating it.

Equally, you should not update the UI, or anything the UI relies on, from outside the context of the EDT, which leaves in you in a conundrum.

Lucky for us, the Swing developers foresaw this issue an provided a number of possible solutions, in your case, the best is probable the good old Swing Timer

Start by having a look at Concurrency in Swing and How to use Swing Timers for more details.

I should also add, Timers (and Thread.sleep) in inherently inaccurate, only guaranteeing "at least" accuracy. Instead of using a counter to keep track of how long they have been running, you should make use of the java.time API instead, for example

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • alright thank you ill check it out later this was my first attempt so i kinda took a shot in the dark but thanks for referring some sources. Also yeah i noticed that the timer module was a few hundred miliseconds off every count, or so. – DudeManGuy Dec 09 '18 at 07:25
  • Also how does Thread.sleep block it? does it occupy the thread? – DudeManGuy Dec 10 '18 at 00:52
  • `Thread.sleeps` STOPS the current running thread, this means that the Event Dispatching Thread is not able to process the Event Queue until it leaves the method - so even a long running loop will have an effect – MadProgrammer Dec 10 '18 at 00:56
  • if i were making a button to trigger it, would i have to use a method to do this, or is there any other more efficient way to do it? – DudeManGuy Dec 16 '18 at 01:55
  • The button would need an ActionListener, but the essential idea is, at some point, you need to call start on the Timer – MadProgrammer Dec 16 '18 at 02:00
0

You can refer the following link below:

In the method, you can update your UI component (JLabel for example) with the elapsed time

Java Swing Timer

UVM
  • 9,776
  • 6
  • 41
  • 66