我有这样的事情:
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”。
有什么想法吗?
答案 0 :(得分:12)
是的 - 你基本上阻止了UI线程,所以它永远不会实际更新。
在UI线程中睡觉是一个非常糟糕的主意。
如果你想做这样的事情,你应该使用Timer
。 (我假设您正在使用Swing。如果没有,请编辑您的问题以指明您正在使用的UI框架。)
您还应注意Thread.sleep
是一种静态方法。您正在使用它,就好像它是一个实例方法。不可否认,你碰巧在当前线程上“打电话”,但你的用法表明你认为:
Thread t = new Thread(...);
t.start();
t.sleep(1000);
会使 new 线程休眠。它不会 - 它将使当前线程休眠,因为这是Thread.sleep
始终所做的事情。 IMO让Java以这种方式调用静态方法是错误的 - 如果你正在使用Eclipse,那么可以选择将其作为警告或错误。
答案 1 :(得分:4)
当您的代码等待时,不会处理任何事件
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();
}
});
}
}
答案 2 :(得分:4)
与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教程中的How to Use Swing Timers。
答案 3 :(得分:2)
不阻止Event Dispatch Thread(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's Threading Policy