简体   繁体   English

隐藏组件时停止Swing计时器

[英]Stopping a Swing timer when a component is hidden

I have a Swing timer ( javax.swing.Timer ) which is used to perform some animation within a custom Swing component. 我有一个Swing计时器( javax.swing.Timer ),用于在自定义Swing组件中执行一些动画。

However, this is causing problems - in particular it seems to stop the application from terminating because of the live timer thread even after all windows are closed. 但是,这会导致问题 - 特别是它似乎会因为活动计时器线程停止应用程序终止,即使在所有窗口关闭后也是如此。 Also it would be nice to avoid the overhead of timers running on hidden objects when the animation cannot be seen. 另外,当无法看到动画时,避免计时器在隐藏对象上运行的开销也会很好。

Ideally I'd like to do the following: 理想情况下,我想做以下事情:

  • Stop the timer when the component is hidden 隐藏组件时停止计时器
  • Start the time again whenever the component becomes visible 只要组件可见,就重新开始时间

Is this possible to do (in a thread-safe way of course!) 这可能吗(当然是以线程安全的方式!)

I am skeptical of your first premise: this simple counter-example shows that a running javax.swing.Timer does not preclude EXIT_ON_CLOSE . 我对你的第一个前提持怀疑态度:这个简单的反例表明运行javax.swing.Timer并不排除EXIT_ON_CLOSE The package-private, shared javax.swing.TimerQueue starts a daemon thread, which allows Program Exit . package-private,共享javax.swing.TimerQueue启动一个守护程序线程,允许程序退出 You may be understandably reluctant to rely on this implementation detail, but it may be worth looking for another reason your program fails to exit. 您可能不愿意依赖此实现细节,但可能值得寻找程序无法退出的另一个原因。

If defer to @kleopatra on AncestorListener ; 如果在AncestorListener上推荐@kleopatra; it should allow you to control the Timer as desired. 它应该允许您根据需要控制Timer The duty cycle of a component animation is typical fairly light, and it's usually dominated by rendering; 组件动画的占空比通常相当轻,并且通常由渲染主导; the latter's overhead is small when the component is not visible. 当组件不可见时,后者的开销很小。 It may be worth profiling to verify that the proposed optimization is worth the effort. 可能值得进行分析以验证所提出的优化是值得的。 If so, consider a WindowListener to minimize activity in an inactive or iconified window. 如果是这样,请考虑使用WindowListener来最小化非活动或图标化窗口中的活动。

Addendum: A now deleted answer suggested overriding setVisible() to condition the timer. 附录:现在删除的答案建议覆盖setVisible()来调节计时器。 While superficially appealing, the approach is brittle and scales poorly. 虽然表面上很吸引人,但这种方法很脆弱,而且规模很小。 The listener approach leverages the observer pattern commonly used in Swing architecture . 侦听器方法利用Swing架构中常用的观察器模式

The event queue should be quiet for one second for the shutdown to be initialized. 事件队列应该安静一秒钟,以便初始化关闭。 That is a hard-coded value in AWTAutoShutdown class. 这是AWTAutoShutdown类中的硬编码值。

So if your swing timer keeps generating events, less then a second apart, that would keep the application from terminate. 因此,如果您的挥杆计时器持续生成事件,相隔不到一秒,这将使应用程序无法终止。

Look at this example (below). 看看这个例子(下面)。 It would not terminate, because the thread, even though it marked as deamon, keeps adding events to the queue. 它不会终止,因为线程即使标记为deamon,也会不断向队列添加事件。 If we increase the sleep to 1500 (1.5 seconds) - it would terminate happily. 如果我们将睡眠时间增加到1500(1.5秒) - 它会很快地终止。

public static void main(String[] args)
{
    Thread thread = new Thread(new Runnable()
    {
        @Override
        public void run()
        {
            while (true)
            {
                // Submit an empty event to the queue
                EventQueue.invokeLater(new Runnable()
                {
                    @Override
                    public void run()
                    {
                    }
                });
                try
                {
                    Thread.sleep(500);
                }
                catch (InterruptedException e)
                {
                    throw new IllegalStateException(e);
                }
            }
        }
    });
    thread.setDaemon(true);
    thread.start();
}

We do it like this: 我们这样做:

  private static final class DisplayabilityListener implements HierarchyListener {
  private final JComponent component;
  private final Timer timer;

  private DisplayabilityListener(JComponent component, Timer timer) {
     this.component = component;
     this.timer = timer;
  }

  @Override
  public void hierarchyChanged(HierarchyEvent e) {
     if ((e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) > 0) {
        if (component.isDisplayable()) {
           timer.start();
        } else {
           timer.stop();
        }
     }
  }

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM