Java Swing - 鼠标移动事件响应缓慢

4

我目前在Java-Swing中遇到了mouseMoved事件的问题。简而言之,我有一个JPanel,并已将MouseMotionListener附加到其中,以便动态隐藏或显示JScrollPane:

myPanel.addMouseMotionListener(new MousePresenter());

我有自己的类,实现了MouseMotionListener接口:

public class MousePresenter implements MouseMotionListener { 

  public void mouseMoved(MouseEvent e) {
   int x = e.getX();
   int y = e.getY();

   if (x>20 && x<200) {
    hideScrollBar();
   }
   else {
    showScrollBar();
   }

  }

} 

问题在于 mouseMoved 事件触发的频率不够高。是否有任何相关的解决方案,同时使用 MouseMotionListener? 感谢您的时间。

不够频繁地触发 - 到底什么是足够或不够?通常情况下,不应该有什么问题,所以你的代码其他地方(或者可能是期望值:你不能获得纳秒分辨率 :-))出了问题。请展示一个SSCCE(如果你不知道这个术语,请谷歌一下),以演示这个问题。 - kleopatra
可能是我的代码有问题,正如你所提到的。里面一定有某种“性能缺陷”导致了延迟。感谢你的努力,我会尝试解决它。 - Karel Burda
1
你面临的问题可能是由于某些操作系统优化引起的。它不是在每个确切的位置更改时触发,而是合并调用以使调用更快、更有效,以免淹没事件队列。您可以通过在鼠标事件发生的屏幕上绘制点来跟踪此操作,鼠标移动得越快,点之间的距离就越远。 - MadProgrammer
5个回答

2
以下内容对我来说似乎完全正常。请注意,事件的处理速度相当快:
  public static void main( String[] args ) {
    EventQueue.invokeLater( new Runnable() {
      @Override
      public void run() {
        JFrame frame = new JFrame( "TestFrame" );
        JPanel content = new JPanel( new BorderLayout() );

        final JLabel mousePosition = new JLabel( "Unknown" );
        content.add( mousePosition, BorderLayout.NORTH );

        content.addMouseMotionListener( new MouseMotionAdapter() {
          @Override
          public void mouseMoved( MouseEvent e ) {
            mousePosition.setText( "X: " + e.getX() + " Y: " + e.getY() );
          }
        } );
        frame.setContentPane( content );
        frame.setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE );
        frame.pack();
        frame.setVisible( true );
      }
    } );
  }

这可能不适用于你的hideScrollBar方法。

1

鼠标移动事件本质上是缓慢的,因为它在每个像素变化时都会触发。

你能做的唯一优化整个问题的方法就是优化回调处理程序内部的操作。在你的情况下,你确实有

if (something)
  doA();
else
  doB();

这意味着无论何种情况下,您都要尝试显示或隐藏滚动条,即使它已经显示或隐藏。您可以做的是:
if (scrollBarIsVisible && x>20 && x<200) {
  hideScrollBar();
  scrollBarIsVisible = false;
}
else if (!scrollBarIsVisible) {
  showScrollBar();
  scrollBarIsVisible = true;
}

这样,当从边界内部切换到外部并反之时,您只需修改元素的可见性(这可能是一项繁重的操作,因为它可能需要重新布局),从而降低计算操作量。


1
谢谢您的回复。实际上我的代码已经非常优化了,我只是为了清晰起见提供了上面的示例,并且只有在滚动条可见时才隐藏它,就像您的示例一样 :) 但问题在于mouseMoved事件响应速度较慢。 - Karel Burda
实际上,你可以做的唯一优化就是测量。如果不进行测量,你将无法知道在何处以及如何进行优化。这种通过将逻辑和奇怪的标志强加于监听器代码来假设进行微小改进的方法,迟早会回过头来对你造成影响。而且可能根本没有可衡量的效果(这只是我的假设 :-))。 - kleopatra
鼠标移动事件本质上是缓慢的,因为它在每个像素变化时都会触发。但这并不慢:如果没有像素变化,就不会有需要通知的移动;-) - kleopatra

1
如果所有您的代码都在事件分派线程中执行,可能会导致问题。请参阅此 trail 并尝试将任何执行大量工作的代码放入 SwingWorker 线程中。

我怀疑他的应用程序做的比上面简短的代码片段列出的更多。 - lotophage
无论如何,问题仍然存在。如果我删除hideScrollBar()和showScrollBar()的调用,整个mouseMoved方法仍然会被缓慢触发。问题在于,当我将MouseMotionListener附加到JList时,事件被触发得非常快 :) - Karel Burda
@KarelBurda 请慢慢说明。我回答中的代码片段表现得正如我所期望的那样,并且一点也不慢。 - Robin
你的代码片段运行速度非常快,而我的GUI相当复杂,这可能是原因。我将尝试将整个代码的某些部分放入SwingWorker线程中。当我将MouseMotionListener附加到我的JPanel时,它每5秒触发了3个事件。但是当我将其附加到我的JList时,它每1秒触发了10个事件。 - Karel Burda
@Karel Burda 把整个代码放到 SwingWorker 线程中时要小心:SwingWorker 不能 帮助处理必须在 EDT 上发生的事情。如果我是你,我会先尝试隔离瓶颈(可能不是事件/处理,所以可以安全地将 其他 东西放在工作线程中 :-) - kleopatra
显示剩余5条评论

1

你的代码优化得不是很好。目前情况下,它总是会调用show或hide Scrollbar方法。你应该修改它,只有在可见时才隐藏它,在隐藏时才显示它。


谢谢您的回复。实际上我的代码已经非常优化了,我只是为了清晰起见提供了上面的示例,并且仅在滚动条可见时隐藏它 :) - Karel Burda
2
我们应该假设这样的检查(如果有的话)是在隐藏/显示方法中完成的(尽管我不认为这是真正必要的:组件通常会用相同的值保护自己免受不必要的重置,虽然在这种情况下没有看到 :) 一般规则(好吧:我的规则)是尽可能少地将逻辑放入侦听器中,只需将课程方向传递给某个知道所有细节的方法,不要将它们涂抹在各个地方。 - kleopatra
@kleopatra JComponent#setVisible确实可以做到这一点。我刚刚在源代码中检查了它,并且正要开始我的评论,但你比我更快。 - Robin

0
问题已解决。我的应用程序存在某些性能问题,导致了这样的延迟。感谢您所提供的信息和建议。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接