0

I'm reading a media with vlcj and I would like to display the time elapsed and the remaining time in some JLabels. I wrote some code but it seems my JLabel.setText don't refresh more that 2 times per second.

To make some more try and being sure that it's not the vlcj's thread that would have some troubles, I wrote a very code with a JLabel. The aim of this simple code is to update the JLabel 10 times per seconds.

Here is my code :

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import javax.swing.JFrame;
import javax.swing.JLabel;

public class TestLabel extends JFrame implements Runnable{
JLabel label = new JLabel("0");
int i=0;
TestLabel() {
    this.setTitle("Test");
    this.setSize(200, 200);
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setContentPane(label);
    this.setVisible(true);      
}

public static void main(String[] args) {
    TestLabel tLabel = new TestLabel();
    Thread t1 = new Thread(tLabel);
    t1.start();
}

@Override
public void run() {
    ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
    scheduler.scheduleAtFixedRate(new Runnable() {
        @Override
        public void run() {
            i+=1;
            System.out.println(i);
            label.setText(String.valueOf(i));               
        }           
    }, 0, 100, TimeUnit.MILLISECONDS);      
}
}

Result : in the console, I get 1, 2, 3, 4... But in the JLabel, I have something like : 1, 2, 3 (...) 32, 37, 42, 47. It seems that the System.out.println write each "i", but the JLabel don't. Why do I have this artefact ?

Thank you for all your reply. Regards.

Dr_Click
  • 449
  • 4
  • 16

3 Answers3

2

You need to call the SwingUtilities.invokeLater method to properly update your GUI text while using Swing (i.e. JFrame, JLabel, etc).

public void run() {
    i+=1;
    System.out.println(i);
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            label.setText(String.valueOf(i));               
        }           
    }); 
}

For more information about SwingUtilities.invokeLater, check out this SO post.

Community
  • 1
  • 1
hsirkar
  • 769
  • 1
  • 8
  • 19
2

Thou shalt not use swing components from a thread other than the event dispatch thread.

So, either use a Swing Timer rather than a ScheduledExecutorService, or wrap the label change into SwingUtilities.invokeLater().

BTW, the call to new TestLabel(); should also be wrapped into SwingUtilities.invokeLater(). Read the swing concurrency tutorial.

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

Don't use a ScheduledExecutorService. Swing components need to be updated on the Event Dispatch Thread (EDT).

Instead you should be using a Swing Timer. Read the section from the Swing tutorial on How to Use Timers for more information.

Here is a simple example using a Timer: How to make JScrollPane (In BorderLayout, containing JPanel) smoothly autoscroll. Just change the interval to 100, instead of 1000.

Community
  • 1
  • 1
camickr
  • 321,443
  • 19
  • 166
  • 288