让我们开始的事实,Swing不是线程安全的,所有交互和修改UI应该在事件指派线程的contentext内进行。
这也意味着您不会在事件调度线程的上下文中执行任何长时间运行或耗时的操作,因为这将阻止它处理EventQueue
上的新事件,包括重新绘制请求。
查看Concurrency in Swing了解更多详情。
最简单的解决方案是使用javax.swing.Timer
。这将允许你安排这是保证要在美国东部时间范围内引发了普通回拨,使其安全地更新UI
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class RandomLabels {
public static void main(String[] args) {
new RandomLabels();
}
public RandomLabels() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JLabel label;
private Random rnd;
public TestPane() {
setLayout(new GridBagLayout());
label = new JLabel();
add(label);
rnd = new Random();
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
label.setText(Integer.toString(rnd.nextInt()));
}
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
这也意味着你可以控制Timer
,启动它,并停止它当你想/需要轻松。
您可以使用Thread
,但管理要求会增加......您将负责管理UI更新的同步,并且必须实现功能以实际停止线程。
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class RandomLabels {
public static void main(String[] args) {
new RandomLabels();
}
public RandomLabels() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JLabel label;
private Random rnd;
public TestPane() {
setLayout(new GridBagLayout());
label = new JLabel();
add(label);
rnd = new Random();
Thread t = new Thread(new Randomizer());
t.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public class Randomizer implements Runnable {
@Override
public void run() {
while (true) {
try {
EventQueue.invokeAndWait(new Runnable() {
@Override
public void run() {
label.setText(Integer.toString(rnd.nextInt()));
}
});
} catch (InterruptedException | InvocationTargetException exp) {
exp.printStackTrace();
}
try {
Thread.sleep(40);
} catch (InterruptedException ex) {
}
}
}
}
}
}
另一种解决办法可能是使用SwingWorker
(不是使用Thread
更好)。这将允许您在后台执行长时间运行/阻塞/耗时的操作,但提供了将更新自动轻松发送回UI的功能。
采取在How to use Swing Timers和Worker Threads and SwingWorker细看了解更多详情
最后,看看Initial Threads。您必须确保您的UI在EDT的环境中启动/构建以及...
您是否考虑过放置计时器以允许您阅读新标签? (随后刷新帧) – mlwn 2014-08-30 16:40:47
是的。尽管没有使用线程,程序仍然等待计时器完成。 – Rane 2014-08-30 16:51:49
阅读http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html和http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html – 2014-08-30 16:57:19