奇怪的bug - 如何暂停java程序?

时间:2012-03-24 16:31:20

标签: java swing concurrency

我正在努力:

  1. 在jLabel中显示文本,
  2. 等两秒钟,
  3. 然后在jLabel
  4. 中写一个新文本

    这应该很简单,但我得到一个奇怪的错误: 第一个文本永远不会被写入,应用程序只等待2秒钟,然后显示最终文本。这是示例代码:


    private void testButtonActionPerformed(java.awt.event.ActionEvent evt) {    
        displayLabel.setText("Clicked!");
    
        //  first method with System timer
    
        /*
        long t0=  System.currentTimeMillis();
        long t1=  System.currentTimeMillis();
                do{
                    t1 = System.currentTimeMillis();
                }
                while ((t1 - t0) < (2000));
         */    
    
        // second method with thread.sleep()
    
        try {
            Thread.currentThread().sleep(2000);
        } catch (InterruptedException e) {}
    
        displayLabel.setText("STOP"); 
    }
    

    使用此代码,文本“Clicked!”永远不会显示。我只得到2秒 - 暂停,然后是“停止”文本。 我尝试使用循环或Thread.sleep()的系统计时器,但两种方法都给出相同的结果。

3 个答案:

答案 0 :(得分:2)

仅提供有关Andrew Thompson评论的更多背景:EDT负责处理gui更新。如果您使用Thread.sleep(...)阻止它们,那么这些更新也会被阻止。这就是为什么你没有看到第一个文本 - EDT无法在标签上进行更新。

答案 1 :(得分:2)

这是一个可运行的例子,可以完成你所追求的目标。正如Andrew Thompson的评论所述,SwingWorker是解决这个问题的好方法。

基本原则是永远不会阻止Event Dispatch Thread。这是负责重新绘制GUI并响应用户交互的线程,所以如果你在EDT上做一些计算成本高昂的东西,你的GUI就会停止响应。

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.ExecutionException;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingWorker;

public class ButtonTest {
    public static void main(String[] args) {

        // create a frame and a button
        JFrame frame = new JFrame();
        final JButton button = new JButton("Button");
        frame.add(button);

        // add an action listener to the button
        button.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {

                // change the button text right away
                button.setText( "Clicked" );

                // create a SwingWorker which simply waits 2000 milliseconds
                // simulating a computation being performed
                SwingWorker<String, Object> worker = new SwingWorker<String, Object>() {
                    @Override
                    public String doInBackground() {

                        // it's safe to call Thread.sleep( ) here
                        // doInBackground is executed on a separate worker
                        // thread
                        try {
                            Thread.sleep(2000);
                        } catch (InterruptedException e) {
                        }

                        return "Done";
                    }

                    @Override
                    protected void done() {

                        // done() is executed back on the Swing thread
                        // so it's safe to updated the state of the button
                        try {
                            button.setText(get());
                        } catch (Exception e) { }
                    }
                };

                // run the worker
                worker.execute();
            }
        });

        frame.setSize( 300, 300 );
        frame.setVisible( true );
    }
}

答案 2 :(得分:2)

您正在搞乱事件调度程序线程。 这将导致您所看到的不期望的UI行为。如果您计划进行这些类型的动画,请务必阅读@Andrew Thompson建议的内容,并了解您是否可以阅读此内容 - Filthy rich clients

最好使用Swing Timer,如下面的curde示例所示:( 是的,它很粗糙,我不担心停止计时器等):

public class DelayTest  extends JPanel{
    JLabel messageLabel = new JLabel();
    JButton actionButton = new JButton("Click Me");
    String[] messages = {"Clicked", "Stop!"};
    int i=0;
    public DelayTest(){
        super();
        add(messageLabel);
        add(actionButton);
        actionButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                Timer timer = new Timer(1000, new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent arg0) {
                        if(i<=1)
                            messageLabel.setText(messages[i++]);
                    }
                });
                timer.start();

            }

        });
    }

}

修改
为什么不停止计时器:

           @Override
           public void actionPerformed(ActionEvent evt) {
              if (i <= 1) {
                 messageLabel.setText(messages[i++]);
              } else {
                 ((Timer)evt.getSource()).stop();
              }
           }
        });