Search code examples
javaswingtimerthread-sleep

Possible not to use timer


Hi everyone i would like to ask if is it possible not to use timer in Java netbeans to display on my JLabel all value of my variable "counter" using while loop. Here is my sample code.

int counter = 0;

while (counter < 10)  {
    lblDisplay.setText("Completed " + Integer.toString(counter));
    try {
        Thread.sleep(1000);
        lblDisplay.setText("Completed " + Integer.toString(counter));
    } catch (InterruptedException ex) {
        Logger.getLogger(Increment.class.getName()).log(Level.SEVERE, null, ex);
    }
    counter++;
}

in using of system.out.println it was displayed but in my Label was not.


Solution

  • Yes it's possible to avoid using a Swing Timer to achieve this, but if you did this then:

    • You'd have to make sure that the loop and the Thread.sleep(...) were run in a background thread off of the Swing event thread. If you don't do this, you will freeze the event thread and thus freeze your GUI and render it useless.
    • And then you'd have to make sure that when you only make Swing calls from the background thread, you take pains to queue those calls onto the Swing event dispatch thread. If you don't do this, you will run the risk of causing occasional very hard to debug threading errors.

    Because of the extra work involved and the risk of getting it wrong, you'll find that it is much simpler and safer to just use a Swing Timer. For instance your posted code looks like it's at grave risk of putting the entire GUI/application to sleep since it has both a while loop and a Thread.sleep(...) called without concern for threading.

    For example, without a Timer, your code could look something like (caveat: code not compiled nor tested):

    new Thread(new Runnable() {
        public void run() {
            int counter = 0;
    
            while (counter < 10)  {
                lblDisplay.setText("Completed " + Integer.toString(counter));
                try {
                    Thread.sleep(1000);
                    final int finalCounter = counter;
                    SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
                            lblDisplay.setText("Completed " + finalCounter);
                        }
                    });
                } catch (InterruptedException ex) {
                    Logger.getLogger(Increment.class.getName()).log(Level.SEVERE, null, ex);
                }
                counter++;
            }    
        }
    }).start();
    

    That's a bit more complicated than I like, while the Swing Timer could look like:

    int delay = 1000;
    new Timer(delay, new ActionListener() {
        private int count = 0;
    
        @Override
        public void actionPerformed(ActionEvent e) {
            if (count < 10) {
                lblDisplay.setText("Completed " + counter);
            } else {
                ((Timer) e.getSource()).stop(); // stop the Timer
            }
            counter++;
        }
    }).start();
    

    Which is simpler and safer than the previous.