【问题标题】:Stopping a Swing timer when a component is hidden隐藏组件时停止 Swing 计时器
【发布时间】:2012-09-08 21:49:31
【问题描述】:

我有一个 Swing 计时器 (javax.swing.Timer),用于在自定义 Swing 组件中执行一些动画。

但是,这会导致问题 - 特别是即使在所有窗口都关闭之后,它似乎也会因为实时计时器线程而停止应用程序终止。当看不到动画时,避免在隐藏对象上运行计时器的开销也会很好。

理想情况下,我想做以下事情:

  • 当组件隐藏时停止计时器
  • 只要组件可见,就重新开始计时

这可能吗(当然是以线程安全的方式!)

【问题讨论】:

  • hmm .. 祖先监听器有什么问题(这是我的第一个想法)?
  • 或者你可以添加一个ComponentListener 并在它的componentHidden(...)和componentShown(...)方法中添加timer.start()/stop()
  • @GagandeepBalin 一个 componentListener 只是一种 propertyChangeListener 到单个组件的可见属性,如果 f.i. 不会改变。祖先被隐藏/显示。

标签: java swing animation timer


【解决方案1】:

我对你的第一个前提持怀疑态度:这个简单的counter-example 表明正在运行的javax.swing.Timer 并不排除EXIT_ON_CLOSE。包私有、共享的javax.swing.TimerQueue 启动一个守护线程,它允许Program Exit。您可能不太愿意依赖此实现细节,但可能值得寻找程序无法退出的另一个原因。

如果在AncestorListener 上服从@kleopatra;它应该允许您根据需要控制Timer。组件动画的占空比通常相当轻,通常以渲染为主;当组件不可见时,后者的开销很小。可能值得进行分析以验证建议的优化是否值得付出努力。如果是这样,请考虑使用WindowListener 以最大限度地减少非活动或图标化窗口中的活动。

附录:一个现已删除的答案建议覆盖 setVisible() 以调节计时器。虽然表面上很吸引人,但这种方法很脆弱并且扩展性很差。侦听器方法利用了Swing architecture 中常用的observer pattern

【讨论】:

  • 谢谢,这种方法效果很好(实际上我使用了 HeirarchyListener 以便能够捕获其他一些事件,但我认为原理是一样的)。我也认为你在计时器上也是对的,但正如你所说,最好不要依赖这种行为!
  • 供参考,这里有一个相关的example 比较了提到的三个听众。
【解决方案2】:

事件队列应该安静一秒钟,以便初始化关机。这是 AWTAutoShutdown 类中的硬编码值。

因此,如果您的摇摆计时器持续生成事件,间隔不到一秒,这将使应用程序无法终止。

看看这个例子(下)。它不会终止,因为线程,即使它被标记为守护进程,也会不断向队列中添加事件。如果我们将睡眠时间增加到 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();
}

【讨论】:

    【解决方案3】:

    我们这样做:

      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();
            }
         }
      }
    

    }

    【讨论】:

    • 我会将if ((x & y) > 0) 更改为if ((x & y) != 0),因为如果y 设置了它的MSB,它将无法工作。
    猜你喜欢
    • 2017-05-18
    • 2019-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多