如何在不阻塞定时器(Java Swing)的情况下暂停程序执行?

How to pause program execution without blocking a Timer (Java Swing)?

我有一个计时器,可以在游戏事件发生时在屏幕上显示动画。我想要做的是让主执行暂停,直到这个动画结束,但我尝试的一切似乎都阻止了定时器 运行。我试过使用 Thread.sleep() 并在锁定对象上调用 wait() 和 notify(),但结果相同。永远不会调用定时器侦听器的 actionPerformed()。

此代码设置计时器:

protected void showMovingEffect(int steps, Direction dir, AnimatedImageSet imgs) {
    effectsPane.runAnimation(imgs, dir, steps);
    waiting = true;
    while (waiting) {
        synchronized(animationWaitLock) {
            try {
                animationWaitLock.wait();
            } catch (InterruptedException e) {}
        }
    }
}

以及 EffectsPane 对象中的定时器和监听器:

private void runAnimation(AnimatedImageSet ais, Direction dir, int iters) {
        System.out.println("run");
        imgs = ais;
        top = 0;
        left = 0;
        topStep = dir.getRowIncrement() * 10;
        leftStep = dir.getColIncrement() * 10;
        iterations = iters;
        index = 0;
        active = true;
        timer.start();
    }

public void actionPerformed(ActionEvent e) {
        System.out.println(index);
        top += topStep;
        left += leftStep;
        index++;
        currentImage = imgs.getImage(index);
        repaint();
        if (index == iterations) { 
            active = false;
            timer.stop();
            synchronized(animationWaitLock) {
                animationWaitLock.notify();
            }
            waiting = false;
        }
    }

actionPerformed() 开始时的 System.out.println 调用从未被调用,因此 wait() 调用也暂停了计时器,或者有什么东西阻止了它。如果我注释掉 showMovingEffect() 中的 sleep/wait 行,动画会运行,但程序不会暂停。

你可以试试这个:

timer.addActionListener(new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent e) {
        // your code
    }
});

一种方法是显示 modal dialog while the animation proceeds. As discussed here, user interaction will be foreclosed, but background GUI updates in response to the javax.swing.Timer will continue. You can allow the user to dismiss the dialog at any time, as shown here,但此时您可能想放弃动画。

no input from the user is needed.

您可以在动画开始后输入 SecondaryLoop 来阻止用户交互而不显示对话框。

SecondaryLoop loop = Toolkit.getDefaultToolkit()
    .getSystemEventQueue().createSecondaryLoop();
timer.start();
loop.enter();

当动画结束时,exit() SecondaryLoop:

public void actionPerformed(ActionEvent e) {
    …
    if (index == iterations) {
        timer.stop();
        loop.exit ();
        …
    }
}