Java 最大化JFrame会导致MouseMoved事件停止触发
似乎我在Mac OS X上不断发现MouseMotion监听器的更多问题。我又举了一个小例子来说明这个问题Java 最大化JFrame会导致MouseMoved事件停止触发,java,macos,swing,mouseevent,Java,Macos,Swing,Mouseevent,似乎我在Mac OS X上不断发现MouseMotion监听器的更多问题。我又举了一个小例子来说明这个问题 public class TestGUI extends JFrame { Panel panel; public TestGUI() { setSize(1000, 600); setLocationRelativeTo(null); panel = new Panel(); setDefaultCloseOperation(JFrame.EXIT_O
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()
来检查这一点
我在MacOSX10.8.5上使用JDK1.7
有问题的答案对我不适用。事实上,接受答案的测试用例在我的计算机上不起作用。我可以使用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);
}
当您按下“+”符号时,窗口确实会最大化,从而使光标回到面板内部。但是,我没有收到鼠标插入事件。因此,移动鼠标不会触发mouseMoved
事件。就Swing而言,鼠标甚至还没有进入组件。
只有当再次将鼠标移到最大化窗口外并重新进入时,才会出现mouseEntered
事件,并再次触发mouseMoved
根据,它在JDK8中解决。在我的机器上进行了测试,事实上,切换到JDK8解决了这个问题。如果这不是您的选择,您可以尝试使用另一个问题中提到的变通方法。如果问题中链接的答案没有帮助,那么您可以用另一种方法来解决这个问题
您可以使用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
)来停止记录鼠标在窗口外的情况
我发现有可能需要使用setPreferredSize
和pack()
来计算边界尺寸。我不确定,但我相信在java 7+版本中会发生这种情况。您的代码在我的Windows 7机器上运行良好。1+回答你的问题,让我们拭目以待,看看答案是什么。