簡體   English   中英

Java:mytextarea.setText(“hello”)+ Thread.sleep(1000)=奇怪的結果

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM