我的JLabel没有快速刷新。为什么?

时间:2016-01-10 16:52:03

标签: java jlabel java-threads

我正在用vlcj阅读媒体,我想在一些JLabel中显示已用时间和剩余时间。我写了一些代码,但似乎我的JLabel.setText不会每秒刷新2次。

为了更多尝试并确保它不是vlcj的线程会有一些麻烦,我用JLabel编写了一个代码。这个简单代码的目的是每秒更新JLabel 10次。

这是我的代码:

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);      
}
}

结果:在控制台中,我得到1,2,3,4 ......但是在JLabel中,我有类似的东西:1,2,3(...)32,37,42,47。似乎System.out.println写了每个" i",但JLabel没有。为什么我有这个人工制品?

感谢您的回复。问候。

3 个答案:

答案 0 :(得分:2)

在使用Swing(即SwingUtilities.invokeLaterJFrame等)时,您需要调用JLabel方法来正确更新GUI文本。

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

有关SwingUtilities.invokeLater的更多信息,请查看this SO post。

答案 1 :(得分:2)

您不得使用事件派发线程以外的线程中的swing组件。

因此,要么使用Swing Timer而不是ScheduledExecutorService,要么将标签更改包装到SwingUtilities.invokeLater()

顺便说一句,对new TestLabel();的调用也应包含在SwingUtilities.invokeLater()中。阅读swing concurrency tutorial

答案 2 :(得分:1)

不要使用ScheduledExecutorService。需要在Event Dispatch Thread (EDT)上更新Swing组件。

相反,您应该使用Swing Timer。有关详细信息,请阅读How to Use Timers上的Swing教程中的部分。

以下是使用计时器的简单示例:How to make JScrollPane (In BorderLayout, containing JPanel) smoothly autoscroll。只需将间隔更改为100,而不是1000。