【问题标题】:How to pause program execution without blocking a Timer (Java Swing)?如何在不阻塞计时器(Java Swing)的情况下暂停程序执行?
【发布时间】:2016-09-09 02:18:41
【问题描述】:

我有一个计时器,当游戏事件发生时,它会在屏幕上显示动画。我想要做的是让主执行暂停,直到这个动画完成,但我尝试的一切似乎都阻止了 Timer 运行。我尝试使用 Thread.sleep() 并在锁定对象上调用 wait() 和 notify(),但结果相同。 Timer 监听器的 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 对象中的 Timer 和 listener:

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() 调用也正在暂停 Timer,或者有什么东西阻塞了它。如果我在 showMovingEffect() 中注释掉睡眠/等待行,动画会运行,但程序不会暂停。

【问题讨论】:

  • 不要使用睡眠!!!!!
  • 我不是。我正在使用 wait()。

标签: java swing animation timer thread-sleep


【解决方案1】:

一种方法是在动画进行时显示modal dialog。正如here 所讨论的,用户交互将被取消,但响应javax.swing.Timer 的后台GUI 更新将继续。您可以允许用户随时关闭对话框,如 here 所示,但您可能希望在此时放弃动画。

不需要用户输入。

您可以在动画开始后输入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 ();
        …
    }
}

【讨论】:

  • 这不是我要找的,恐怕。我正在寻找一种在启动计时器后暂停的方法,并在完成后重新启动。有一个对话框没有任何用处,因为不需要用户输入。
  • @Leonide:我担心在没有视觉反馈或逃逸机制的情况下阻止用户交互;但对于简短的动画,您可以使用上述SecondaryLoop
  • 可能是切题的问题。我尝试的第一件事是让 runAnimation 方法有一个循环来定期刷新 effectsPane,但是有了这个,它就像我想要的那样暂停,但 effectsPane 不会刷新。知道为什么吗?
  • @Leonide:猜测一下,循环阻塞了现有的事件队列; SecondaryLoop 阻止用户交互但让动画继续进行。
  • +++ 1mio for SecondaryLoop :-), now is searchable here, 到处都是
【解决方案2】:

你可以试试这个:

timer.addActionListener(new ActionListener() {

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

【讨论】:

  • 这有什么帮助?
  • 因为在此代码中,此 actionPerformed 是您的方法,而不是动作侦听器方法。所以如果你想运行它,你必须像effectsPane.runAnimation(imgs, dir, steps);一样调用effectsPane.actionPerformed(java.awt.Event);或将@Override添加到你的actionPerformed方法中
  • 试过这个,但结果相同。 actionPerformed 方法仍然没有被调用。 Timer 是调用 showMovingEffect 的类的成员还是显示动画的 JPanel 是否重要?
猜你喜欢
  • 2018-06-05
  • 1970-01-01
  • 2021-11-25
  • 1970-01-01
  • 2010-10-23
  • 1970-01-01
  • 2011-01-19
  • 2022-12-10
相关资源
最近更新 更多