【问题标题】:Maximizing a JFrame causes MouseMoved events to stop firing最大化 JFrame 会导致 MouseMoved 事件停止触发
【发布时间】:2014-12-06 06:43:07
【问题描述】:

我似乎不断发现 Mac OS X 上的 MouseMotion 侦听器存在更多问题。我制作了另一个小示例来说明问题。

public class TestGUI extends JFrame {

Panel panel;

public TestGUI()
{
    setSize(1000, 600);
    setLocationRelativeTo(null);
    panel = new Panel();
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    getContentPane().add(panel);
    setVisible(true);
}

class Panel extends JPanel
{
    private Point mouseLocation = new Point();
    public Panel()
    {
        addMouseMotionListener(new MouseAdapter() {
            @Override
            public void mouseMoved(MouseEvent e)
            {
                mouseLocation = e.getPoint();
                repaint();
            }
        });
        setVisible(true);
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        g.setColor(Color.BLACK);
        g.drawString("(" + mouseLocation.x + "," + mouseLocation.y + ")", 100, 100);
    }
}

public static void main(String[] args) {
    new TestGUI();
}
}

我不确定这是否发生在 windows 上,因为我目前无法访问 windows 计算机,但在 OS X 上会发生以下情况:

单击绿色“+”以最大化窗口会使窗口最大化,从而使鼠标指针回到画布区域。但是,如果您不单击,则说明鼠标位置的文本将停止更新。

我知道这不是窗口失去焦点:我通过在面板中添加一个 focusAdapter 并在方法中添加一个 System.out.println() 来检查这一点。

我在 Mac OS X 10.8.5 上使用 JDK 1.7

this 问题中的答案对我不起作用。事实上,接受答案的测试用例在我的电脑上不起作用。

【问题讨论】:

  • 您的代码在我的 Windows 7 机器上运行良好。 1+ 到您的问题,让我们拭目以待,看看会以这种方式得到什么答案。

标签: java macos swing mouseevent


【解决方案1】:

我可以使用 JDK1.7 在 OS X 10.9.3 上重现该问题。

我看到的情况是,当您将鼠标移动到包含绿色“+”符号的窗口装饰栏时,您的鼠标将离开面板。这可以通过附加MouseListener 来查看

public Panel()
{
  addMouseListener( new MouseAdapter() {
    @Override
    public void mouseEntered( MouseEvent e ) {
      System.out.println( "TestGUI.Panel.mouseEntered" );
    }

    @Override
    public void mouseExited( MouseEvent e ) {
      System.out.println( "TestGUI.Panel.mouseExited" );
    }
  } );
  addMouseMotionListener(new MouseAdapter() {
    @Override
    public void mouseMoved(MouseEvent e)
    {
      mouseLocation = e.getPoint();
      repaint();
    }
  });
  setVisible(true);
}

当您按下“+”符号时,窗口确实会最大化,导致您的光标回到面板内。但是,我没有收到mouseEntered 事件。所以就Swing而言,移动鼠标不会触发mouseMoved事件,鼠标甚至还没有进入组件。 仅当再次将鼠标移出最大化窗口并重新进入时,我才会收到mouseEntered 事件并再次触发mouseMoved

根据this question,在JDK8中已解决。在我的机器上进行了测试,确实,切换到 JDK8 解决了这个问题。如果这不适合您,您可以尝试使用其他问题中提到的解决方法。

【讨论】:

    【解决方案2】:

    如果问题中链接的答案没有帮助,那么您可以通过其他方式解决此问题。

    除了使用mouseMotionAdapter(或Listener),您还可以使用ScheduledExecutorService(或其他类型的计时器,如果您愿意),以恒定速率获得鼠标位置。窗口甚至不必为您设置焦点。

    下面的小程序演示了最大化窗口对鼠标位置的跟踪没有任何影响。

    public class TestGUI extends JFrame {
    
    Panel panel;
    Point mouseLocation = new Point();
    Dimension borderSize = new Dimension();
    ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
    public TestGUI()
    {
        setSize(1000, 600);
        setLocationRelativeTo(null);
        panel = new Panel();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().add(panel);
        setVisible(true);
        borderSize.setSize(getSize().width - getContentPane().getSize().width, getSize().height - getContentPane().getSize().height);
        ex.schedule(new UpdatingService(), 10, TimeUnit.MILLISECONDS);
    }
    
    class Panel extends JPanel
    {
        public Panel()
        {
            setVisible(true);
        }
    
        @Override
        protected void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            g.setColor(Color.BLACK);
            g.drawString("(" + mouseLocation.x + "," + mouseLocation.y + ")", 100, 100);
        }
    }
    
    private void checkMouse()
    {
        mouseLocation.x = MouseInfo.getPointerInfo().getLocation().x - this.getLocationOnScreen().x - borderSize.width;
        mouseLocation.y = MouseInfo.getPointerInfo().getLocation().y - this.getLocationOnScreen().y - borderSize.height;
        repaint();
    }
    
    class UpdatingService implements Runnable
    {
        @Override
        public void run()
        {
            checkMouse();
            ex.schedule(new UpdatingService(), 10, TimeUnit.MILLISECONDS);
        }
    }
    
    public static void main(String[] args) {
        new TestGUI();
    }
    }
    

    程序的工作原理如下:首先它计算窗口边框的大小,这因计算机而异。然后每 10 毫秒ScheduledExecutorService 获取鼠标在屏幕上的位置(这可能过于频繁,玩弄延迟,看看是否有最佳时间)。它首先在整个屏幕上找到鼠标的位置,然后减去JFrame 的位置,最后减去边框的粗细。

    值得注意的是,这个程序会继续跟踪窗口外的鼠标,但是如果鼠标在窗口外,可以编写一个简单的 if 语句(或使用MouseAdapter)来停止记录。

    我发现可能需要使用setPreferredSizepack() 才能进行边框尺寸计算。我不确定,但我相信这发生在 java 7+ 版本中

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-14
      • 2011-12-07
      相关资源
      最近更新 更多