【问题标题】:java wait for swing.timer task to finish before executing the next taskjava 在执行下一个任务之前等待 swing.timer 任务完成
【发布时间】:2017-01-15 01:49:20
【问题描述】:

所以标题真的说明了一切。 在执行方法中的下一个命令之前,我需要线程等待计时器完成。

代码:

import javax.swing.Timer;

public class doesntMatter
{
    Timer timer;
    ActionListener timerTask;

    public doesntMatter
    {
         timerTask = new ActionListener()
         {
              @Override
              public void actionPerformed(ActionEvent e)
              {
                  //taskSomethingIdk
              }
         }
    }

    private void whatever
    {
        timer = new Timer(1000, timerTask);
        timer.setInitialDelay(0);
        timer.start();

        // here i need to wait for the timer to finish

        if(timerhasfrigginfinished)
             continueOrSomethingIdk
    }

}

【问题讨论】:

  • 把它放到定时器的ActionListener中,当它完成重复时再做。
  • 定义“定时器何时完成”?在大多数情况下,计时器会重复,尽管您将它们设置为不重复。在任何情况下,您都可以使用观察者模式,或者在完成后简单地调用其他一些预定义的方法

标签: java swing timer wait activity-finish


【解决方案1】:

假设您的计时器重复,在 Timer 的 ActionListener 中检查它是否正在运行最后一次重复,如果是,那里,调用continueOrSomethingIdk() 方法。

否则,您将不得不建立自己的通知机制,即回调,以便计时器通知所有侦听器它已完成运行。

例如:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

@SuppressWarnings("serial")
public class WhenTimerDone extends JPanel {
    private static final Color[] COLORS = { 
            Color.RED, Color.ORANGE, 
            Color.YELLOW, Color.GREEN,
            Color.BLUE, Color.CYAN };
    private static final String START = "Start";
    private static final String DONE = "Done";
    private static final int PREF_W = 400;
    private static final int PREF_H = PREF_W;
    public static final int TIMER_DELAY = 1000;
    private JLabel statusLabel = new JLabel(START);
    private StartAction startAction = new StartAction("Start!");

    public WhenTimerDone() {
        add(statusLabel);
        add(new JButton(startAction));
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        return new Dimension(PREF_W, PREF_H);
    }

    // this is the method called by the Timer's ActionListener when it is done
    public void done() {
        // reset all to baseline state
        statusLabel.setText(DONE);
        startAction.setEnabled(true);
        setBackground(null);
    }

    // ActionListener for the start button
    private class StartAction extends AbstractAction {

        public StartAction(String name) {
            super(name);
            int mnemonic = (int) name.charAt(0);
            putValue(MNEMONIC_KEY, mnemonic);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            // disables itself
            setEnabled(false);
            statusLabel.setText(START); // updates the status label

            // create and start a timer
            Timer timer = new Timer(TIMER_DELAY, new TimerListener());
            timer.setInitialDelay(0);
            timer.start();    
        }
    }

    // action listener for the timer
    private class TimerListener implements ActionListener {
        private int colorsIndex = 0;

        @Override
        public void actionPerformed(ActionEvent e) {
            // simply loops through a colors array, changing background color
            if (colorsIndex < COLORS.length) {
                setBackground(COLORS[colorsIndex]);
                colorsIndex++;
            } else {
                // when all colors shown -- stop the timer
                ((Timer) e.getSource()).stop();

                // and call the done method -- ******* here's the key!
                done();  // called when Timer is done!
            }
        }
    }

    private static void createAndShowGui() {
        WhenTimerDone mainPanel = new WhenTimerDone();

        JFrame frame = new JFrame("WhenTimerDone");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

【讨论】:

  • 这是最简单的方法......但我想知道计时器何时完成......我不敢相信这不容易
  • @user7419985:查看代码中的 cmets 以解释发生了什么。但是,是的,这就是你需要做的。
  • @user7419985:Swing 计时器没有addChangeListener(...)addPropertyChangeListener(...) 类型的添加通知机制。这是一个简单的构造。
【解决方案2】:

这里的关键字是通知/等待 您的计时器线程应该通知应该等待的另一个线程 像这样:

import javax.swing.Timer;

public class doesntMatter
{
Timer timer;
ActionListener timerTask;

public doesntMatter
{
     timerTask = new ActionListener()
     {
          @Override
          public void actionPerformed(ActionEvent e)
          {
              synchronized(timer){
                  //taskSomethingIdk
                  //you would have to rig something so we can access a common object as the monitor/lock object
                  timer.notify()
              }
          }
     }
}

private void whatever
{
    timer = new Timer(1000, timerTask);
    timer.setInitialDelay(0);
    timer.start();
    //Need to obtain a lock on the "monitor" object
    //Lock will be released while it is waiting
    synchronized(timer){
        timer.wait()
        //do whatever
    }
}

}

这将使“主”线程等待,直到计时器线程调用通知方法,然后唤醒其中一个等待线程。

我也不认为“ActionListener”扩展了“TimerTask”。因此,代码示例可能无法编译,因为您向 Timer 提供了一个 ActionListener,它需要一个 TimerTask 作为输入。或者也许我不明白你的代码应该做什么。

更多信息请参见How to use wait and notify in Java?

【讨论】:

  • 你测试过这段代码吗?看起来它会导致 Swing 事件调度线程等待,这意味着整个 GUI 应该冻结。我不确定这是 OP 想要的行为。
  • 不,我没有测试它。但只有调用“public void 不管()”方法的线程会等到从不同的线程调用 actionPerformed 方法。如果swing调度程序调用“whatever”方法,是的。然后调度程序线程将挂起。但是调用actionPerformed()的线程只会挂起等待获取“timer”对象的锁。
  • 嗯..谢谢你们俩:我试过了,这家伙是对的..它确实冻结了..我想要一个标签来倒计时
  • @Timmeey:调用actionPerformed的线程 EDT,事件调度线程,但我假设你已经知道这一点。将其置于等待状态将完全冻结并呈现无用的 GUI。
  • 如果您在 EDT 中呼叫等待,这将不起作用,只是说 ;)
猜你喜欢
  • 2019-07-26
  • 1970-01-01
  • 2012-01-17
  • 2013-03-22
  • 1970-01-01
  • 1970-01-01
  • 2012-07-23
  • 1970-01-01
  • 2012-04-22
相关资源
最近更新 更多