[英]Java: mytextarea.setText(“hello”) + Thread.sleep(1000) = strange result
我有這樣的事情:
for(int i=0; i<5; i++){
mytextarea.setText("hello " + i);
try{
Thread.currentThread().sleep(1000); //to give time for users to read
} catch(Exception e){}
}
我希望它會在文本區顯示“hello 0”,等待1秒,然后顯示“hello 1”,然后等待1秒等。
但是發生的事情是不同的,等待5秒,然后顯示“你好4”。
任何想法?
是的 - 你基本上阻止了UI線程,所以它永遠不會實際更新。
睡在UI線程中是一個非常糟糕的主意。
如果你想做這樣的事情,你應該使用一個Timer
。 (我假設您正在使用Swing。如果沒有,請編輯您的問題以指明您正在使用的UI框架。)
您還應該注意Thread.sleep
是一個靜態方法。 您正在使用它,就好像它是一個實例方法。 不可否認,你碰巧在當前線程上“打電話”,但你的用法表明你認為:
Thread t = new Thread(...);
t.start();
t.sleep(1000);
會使新線程睡眠。 它不會 - 它會使當前線程休眠,因為這就是Thread.sleep
總是這樣做的。 IMO,Java允許您以這種方式調用靜態方法是錯誤的 - 如果您使用的是Eclipse,則可以選擇將此方法設置為警告或錯誤。
當您的代碼等待時,不會處理任何事件
http://java.sun.com/docs/books/tutorial/uiswing/concurrency/index.html
閱讀javax.swing.SwingUtilities.invokeAndWait()和invokeLater()的javadoc這可能會有所幫助
編輯:感謝Jon和Samuel將所有想法放在一起:
public class Swing extends JPanel {
JTextField textField;
static JTextArea textArea;
static int line = 1;
public Swing() {
super(new BorderLayout());
textArea = new JTextArea(5, 20);
add(textArea);
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("TextDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Swing());
frame.pack();
frame.setVisible(true);
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
textArea.append("Hello " + line++ + "\n");
}
};
if (line < 5) {
new Timer(1000, taskPerformer).start();
}
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
就像Jon Skeet的回答中所解釋的那樣,您應該使用計時器,因為您無法阻止EDT並期望UI更新。 下面是您重寫為使用Swing計時器的示例代碼段。
ActionListener action = new ActionListener() {
int i = 0;
public void actionPerfomed(ActionEvent e) {
mytextarea.setText("hello " + i++);
}
};
new javax.swing.Timer(1000, action).start();
有關計時器功能的更多信息,請參閱Swing教程中的如何使用Swing Timers 。
另一種不阻止事件調度線程 (EDT)的方法是啟動一個新線程:
Thread thread = new Thread(new Runnable() {
@Override
public void runt() {
for (int i=0; i<5; i++) {
mytextarea.setText("hello " + i);
try {
Thread.sleep(1000); //to give time for users to read
} catch (InterruptedException e) {
break; // interrupt the for
}
}
}
});
thread.start();
編輯:
一般來說,Swing不是線程安全的,也就是說,只有在EDT上才能調用未標記為線程安全的Swing方法。 setText()
是線程安全的,所以在上面的代碼中沒問題。
要在EDT上運行代碼,可以使用javax.swing.SwingUtilities(或java.awt.EventQueue)中的invokeAndWait()
或invokeLater()
)。
有關更多詳細信息,請參閱: Swing的線程策略
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.