讓我們開始的事實,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