我正在用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没有。为什么我有这个人工制品?
感谢您的回复。问候。
答案 0 :(得分:2)
在使用Swing(即SwingUtilities.invokeLater
,JFrame
等)时,您需要调用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。