【问题标题】:Delay routine in Swing on button click which should not stall the applicationSwing 中的延迟例程单击按钮不应停止应用程序
【发布时间】:2015-03-07 00:26:24
【问题描述】:

我正在尝试执行以下操作:单击按钮,按钮消失 2 秒,文本显示 2 秒,然后在 2 秒后,可见性反转。到目前为止,我已经这样做了:

btnScan.addActionListener(new ActionListener(){

        @Override
        public void actionPerformed(ActionEvent e) {
            // TODO Auto-generated method stub
            txtScanning.setVisible(true);
            btnScan.setVisible(false);
               try {
                Thread.sleep(2000);                 //1000 milliseconds is one second.
                } catch(InterruptedException ex) {
                Thread.currentThread().interrupt();
                }
               }
            btnScan.setVisible(true);
        }

    });

结果是,只要我单击 btnScan,整个程序就会冻结 2 秒钟,然后再执行任何操作。如何按正确的顺序添加延迟?

【问题讨论】:

  • 使用线程。不要使用Thread#sleep
  • Thread.sleep() 是造成它的原因,它阻塞了 Event Dispatch Thread..,Swing 是单线程的..
  • 字面意思是Thread.sleep() 阻塞了调用它的线程。

标签: java swing sleep


【解决方案1】:

您不应在调度事件的代码中调用 sleep 方法。所有与工作相关的 UI 都由 EDT(Event Dispatch Thread) 处理,并且 sleep 方法将导致它冻结,因此您的 Swing 应用程序将冻结。

要克服它,您应该使用 计时器。运行计时器并使用 SwingUtilities.invokeLater 执行 UI 操作,以便由 EDT 处理。

import java.util.Timer;

// make it a member variable
Timer timer = new Timer();
........
    public void actionPerformed(java.awt.event.ActionEvent evt) {                                       

        button.setVisible(false);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                SwingUtilities.invokeLater(new Runnable() {

                    public void run() {
                        button.setVisible(true);
                    }
                });

            }
        }, 2000);

    }

【讨论】:

    【解决方案2】:

    当前在您的代码中,您正在通过调用 Thread.sleep 导致 EDT(事件调度程序线程)暂停
    在 EDT 中执行任何长时间运行的任务都会导致您的 UI 冻结。

    要实现您的愿望,请使用 SwingWorker 线程来执行您的操作
    这可能会有所帮助:http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html

    【讨论】:

    • 或者使用 Swing a Timer 自动触发其在 EDT 内的事件
    【解决方案3】:

    Swing 是一个单线程环境,任何阻塞该线程的东西都会阻止它处理新事件,包括重绘请求。

    Swing 也不是线程安全的,这意味着您永远不应该从 EDT 上下文之外创建或更新 UI。

    在这种情况下,您可以使用 Swing Timer 来触发在未来某个时间发生的回调(通知)将在 EDT 的上下文中执行,从而可以安全地使用

    查看Concurrency in SwingHow to us Swing Timers 了解更多详情

    【讨论】:

      【解决方案4】:

      利用 Swing 计时器,您可以执行以下操作:

      btnScan.addActionListener(new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
              txtScanning.setVisible(true);
              btnScan.setVisible(false);
              Timer timer = new Timer(2000, new ActionListener() {
                  @Override
                  public void actionPerformed(ActionEvent acv) {
                      btnScan.setVisible(true);
                      txtScanning.setVisible(false);
                  }
              });
      
              // setRepeats(false) to make the timer stop after sending the first event
              timer.setRepeats(false);
              timer.start();
          }
      });
      

      【讨论】:

        猜你喜欢
        • 2013-02-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多