Java Mouse事件未在OSX上注册 [英] Java Mouse Events not registering on OSX

查看:151
本文介绍了Java Mouse事件未在OSX上注册的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用的软件是用Java编写的。这个特殊的问题只在Mac上表现出来,程序在Windows和Linux上正常运行。



我基本上写了一个自定义的工具提示,它围绕着应用程序主窗口的鼠标。它实际上是一个单独的,未装饰的框架(我们将调用显示框架),它改变了基于鼠标移动的窗口接收的mouseMoved事件的位置。默认位置略低于光标的右侧,但是当它到达窗口的边缘时,它可以翻转到光标的左侧或顶部。这在前面提到的其他平台上正常工作,但是它在mac上显示,这个mouseMoved事件在显示框架之前被某种方式消耗,才能到达主应用程序。所以窗口从来没有接收到mouseMoved事件,因此永远不会移动并跟随光标。显示框只能更改位置,是光标是否进入。然后,主窗口触发mouseExited事件,这会导致显示帧设置为可视(false)(如果光标不在主窗口中,则不想显示显示框)。然后触发一个mouseEntered事件,这会使显示框在下面和右边重新绘制,因为它应该是。



我已经尝试将焦点设置为主窗口当重绘方法被调用时,我已经打印出来.hasFocus()一旦完成,另一个窗口现在有焦点,但仍然没有收到mouseMoved事件。此外,将鼠标监听器放在显示框上不起作用,因为我感兴趣的mouseMoved事件不在displayFrame的实际框架内,所以这些也不会被触发。



很奇怪的是,有一种办法可以在Mac上产生正确的行为。使显示框跟随鼠标是一个可以在应用程序内选择的工具模式。在此模式下,用户还可以向主窗口添加附加功能。如果用户在此模式下离开点击,会弹出一个小对话框,要求您命名新功能,如果您这样做,单击确定,或不点击取消,现在显示框将跟随鼠标周围。如果您移动得太快,并且可以将光标放在显示框内,然后再重新绘制,那么您可以再次打破它,然后再回到正方形,不能跟随你。



对话框需要在显示时设置父级,我们认为可能将主窗口设置为父窗口,而不知何故,当它出现然后离开时,鼠标事件传递给父母。但是,对话框将其父对象设置为显示框。所以这也是不幸的。



这个问题发生在各种版本的osx和不同版本的Java上。作为参考,我正在运行10.9.2,但是它已经在10.9.3,10.9.4和10.8,10.6上被复制了。
我正在运行Java 1.7.0_51和1.7.0_67。



我花了一些时间在网上查找,没有提供任何真正帮助的东西并希望从这里得到任何帮助。下面是一个更简单的示例程序,我写的复制了我遇到的问题。



谢谢。
package mouseMovedProblem;

  import java.awt.BorderLayout; 
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.event.MouseInputListener;

public class MainFrame extends JPanel {
public static MainFrame mainFrame;

MainFrame(){
// setOpaque(false);
setBackground(Color.WHITE);
MouseListener ml = new MouseListener();
addMouseListener(ml);
addMouseMotionListener(ml);
}

私有类MouseListener实现MouseInputListener {
public void mouseClicked(MouseEvent e){
// System.out.println(Mouse clicked);
DisplayFrame.showDisplay(e.getX(),e.​​getY());
String test = JOptionPane.showInputDialog(DisplayFrame.getInstance(),
这是一个测试,测试);
}
public void mousePressed(MouseEvent e){
// DisplayFrame.showDisplay(e.getX(),e.​​getY());
}
public void mouseReleased(MouseEvent e){
// DisplayFrame.showDisplay(e.getX(),e.​​getY());
}
public void mouseEntered(MouseEvent e){
// DisplayFrame.showDisplay(e.getX(),e.​​getY());
}
public void mouseExited(MouseEvent e){
DisplayFrame.getInstance()。setVisible(false);
}
public void mouseDragged(MouseEvent e){
// TODO自动生成的方法存根
}
public void mouseMoved(MouseEvent e){
// System.out.println(Mouse moved);
DisplayFrame.showDisplay(e.getX(),e.​​getY());
}
}

public static MainFrame getInstance(){
if(mainFrame == null){
mainFrame = new MainFrame();
}
尺寸大小=新尺寸(900,700);
mainFrame.setPreferredSize(size);
mainFrame.setMinimumSize(size);

return mainFrame;
}

public static void main(String args []){
JFrame frame = new JFrame();
frame.setLayout(new BorderLayout());
frame.add(getInstance(),BorderLayout.CENTER);
frame.pack();

frame.setVisible(true);
}

}

class DisplayFrame extends JFrame {
public static DisplayFrame display;

DisplayFrame(){
setUndecorated(true);
JPanel panel1 = new JPanel();
panel1.setBackground(Color.BLACK);
JPanel panel2 = new JPanel();
panel2.setBackground(Color.WHITE);
JTabbedPane tPane = new JTabbedPane();
tane.setTabPlacement(JTabbedPane.BOTTOM);
tPane.addTab(Black,panel1);
tPane.addTab(White,panel2);
add(tPane);
}

public static DisplayFrame getInstance(){
if(display == null){
display = new DisplayFrame();
}

//设置大小
尺寸size = new Dimension(200,200);
display.setPreferredSize(size);
display.setMinimumSize(size);
display.setMaximumSize(size);

返回显示;
}

public static void showDisplay(int x,int y){
getInstance();

int compX =(int)MainFrame.getInstance()。getLocationOnScreen()。getX();
int compY =(int)MainFrame.getInstance()。getLocationOnScreen()。getY();
//应该是位于右边的10个像素,光标下方的20个像素
int newX = compX + x + 10;
int newY = compY + y + 20;

//设置位置
display.setLocation(newX,newY);

if(!display.isVisible()){
display.setVisible(true);
}
//这是为了确保框架没有隐藏在主窗口后面
display.toFront();

} // end method
}


解决方案

一旦我更正你的代码,这样编译和运行,我没有问题你的例子...



MacOS X 10.9.4, Java 1.8.0_05。



如果屏幕上有其他组件已注册 MouseListener MouseMoitionListener ,它们将阻止到父组件的事件。有一个技巧可以用来克服这个问题,这是一个更多的工作,但它的工作。



基本上,你可以注册一个 AWTListener 工具包蒙版以提供 MOUSE_MOTION_EVENT_MASK 事件。这是全球性的,所以您将收到通过事件队列的所有鼠标运动事件,因此您需要适当地过滤它们,例如...

  import java.awt.AWTEvent; 
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class MainFrame extends JPanel {

MainFrame(){
// setOpaque(false);
setBackground(Color.WHITE);
MouseListener ml = new MouseListener();
addMouseListener(ml);
addMouseMotionListener(ml);

Toolkit.getDefaultToolkit()。addAWTEventListener(new AWTEventListener(){

@Override
public void eventDispatched(AWTEvent event){
MouseEvent evt = (MouseEvent)事件;
点p = evt.getPoint();
if(evt.getSource()!= MainFrame.this){
p = SwingUtilities.convertPoint(evt.getComponent() ,p,MainFrame.this);
}
if(MainFrame.this.getBounds()。contains(p)){
System.out.println(px +x+ py );
}
}
},AWTEvent.MOUSE_MOTION_EVENT_MASK);
}

私有类MouseListener扩展MouseAdapter {

public void mouseClicked(MouseEvent e){
// System.out.println(Mouse clicked );
DisplayFrame.showDisplay(e.getX(),e.​​getY());
}

public void mousePressed(MouseEvent e){
// DisplayFrame.showDisplay(e.getX(),e.​​getY());
}

public void mouseReleased(MouseEvent e){
// DisplayFrame.showDisplay(e.getX(),e.​​getY());
}

public void mouseEntered(MouseEvent e){
// DisplayFrame.showDisplay(e.getX(),e.​​getY());
}

public void mouseExited(MouseEvent e){
DisplayFrame.getInstance()。setVisible(false);
}

public void mouseDragged(MouseEvent e){
// TODO自动生成的方法存根
}

public void mouseMoved MouseEvent e){
System.out.println(Mouse moved+ e.getX()+x+ e.getY());
DisplayFrame.showDisplay(e.getX(),e.​​getY());
}
}

private static MainFrame mainFrame;

public static MainFrame getInstance(){
if(mainFrame == null){
mainFrame = new MainFrame();
mainFrame.setLayout(new GridBagLayout());

JPanel blocker = new JPanel();
blocker.setBackground(Color.RED);
blocker.setPreferredSize(new Dimension(200,200));
MouseAdapter ma = new MouseAdapter(){
};
blocker.addMouseListener(ma);
blocker.addMouseMotionListener(ma);
mainFrame.add(blocker);

尺寸大小=新尺寸(900,700);
mainFrame.setPreferredSize(size);
mainFrame.setMinimumSize(size);
}

return mainFrame;
}

public static void main(String args []){
EventQueue.invokeLater(new Runnable(){
@Override
public void run (){
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch(ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex){
ex.printStackTrace() ;
}

JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(getInstance(),BorderLayout.CENTER);
frame.pack();

frame.setVisible(true);
}
});
}

static class DisplayFrame extends JFrame {

public static DisplayFrame display;

DisplayFrame(){
setUndecorated(true);
JPanel panel1 = new JPanel();
panel1.setBackground(Color.BLACK);
JPanel panel2 = new JPanel();
panel2.setBackground(Color.WHITE);
JTabbedPane tPane = new JTabbedPane();
tane.setTabPlacement(JTabbedPane.BOTTOM);
tPane.addTab(Black,panel1);
tPane.addTab(White,panel2);
add(tPane);
}

public static DisplayFrame getInstance(){
if(display == null){
display = new DisplayFrame();
}

//设置大小
尺寸尺寸=新尺寸(200,200);
display.setPreferredSize(size);
display.setMinimumSize(size);
display.setMaximumSize(size);

返回显示;
}

public static void showDisplay(int x,int y){
getInstance();

int compX =(int)MainFrame.getInstance()。getLocationOnScreen()。getX();
int compY =(int)MainFrame.getInstance()。getLocationOnScreen()。getY();
//应该是位于右边的10个像素,光标下方的20个像素
int newX = compX + x + 10;
int newY = compY + y + 20;

//设置位置
display.setLocation(newX,newY);

if(!display.isVisible()){
display.setVisible(true);
}
//这是为了确保框架没有隐藏在主窗口后面
display.toFront();

} // end method
}
}

这个例子将打印鼠标的x / y位置。您将看到,当您的 MouseMoitionListener 停止接收事件时, AWTListener 容器打印出结果。



更新



我可以使用Java 1.7.0_15测试它,并且能够复制该问题。这似乎是Java 7中的一个错误,因为即使 AWTListener 停止显示输出...



所以有什么解决方案?升级到Java 8 ...



好的,如果你不能这样做,你可以使用黑客工作...基本上,你开始线程 javax.swing.Timer 哪些探测 java.awt.MouseInfo 对于 java.awt.PointerInfo ,并确定光标在屏幕上的位置,例如...

 定时器定时器=新的定时器(40,新的ActionListener(){
@Override
public void actionPerformed(ActionEvent e){
PointerInfo pi = MouseInfo.getPointerInfo();
Point p = pi.getLocation();
SwingUtilities.convertPointFromScreen(p,MainFrame.this);
if(MainFrame.this.getBounds() (p)){
System.out.println(pi =+ px +x+ py);
}
}
});
timer.start();

重要的是:


  1. 确保鼠标指针位于组件的范围内,

  2. 确保在更新任何内容之前已更改

作为一个例子...

  import java.awt.AWTEvent ; 
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class MainFrame extends JPanel {

MainFrame(){
// setOpaque(false);
setBackground(Color.WHITE);
MouseListener ml = new MouseListener();
addMouseListener(ml);
addMouseMotionListener(ml);

Toolkit.getDefaultToolkit()。addAWTEventListener(new AWTEventListener(){

@Override
public void eventDispatched(AWTEvent event){
MouseEvent evt = (MouseEvent)事件;
点p = evt.getPoint();
if(evt.getSource()!= MainFrame.this){
p = SwingUtilities.convertPoint(evt.getComponent() ,p,MainFrame.this);
}
if(MainFrame.this.getBounds()。contains(p)){
System.out.println(px +x+ py );
}
}
},AWTEvent.MOUSE_MOTION_EVENT_MASK);

定时器定时器=新的定时器(40,新的ActionListener(){
@Override
public void actionPerformed(ActionEvent e){
PointerInfo pi = MouseInfo.getPointerInfo );
Point p = pi.getLocation();
SwingUtilities.convertPointFromScreen(p,MainFrame.this);
if(MainFrame.this.getBounds()。contains(p)){
System.out.println(pi =+ px +x+ py);
}
}
});
timer.start();
}

私有类MouseListener扩展MouseAdapter {

public void mouseClicked(MouseEvent e){
// System.out.println(Mouse clicked );
DisplayFrame.showDisplay(e.getX(),e.​​getY());
}

public void mousePressed(MouseEvent e){
// DisplayFrame.showDisplay(e.getX(),e.​​getY());
}

public void mouseReleased(MouseEvent e){
// DisplayFrame.showDisplay(e.getX(),e.​​getY());
}

public void mouseEntered(MouseEvent e){
// DisplayFrame.showDisplay(e.getX(),e.​​getY());
}

public void mouseExited(MouseEvent e){
DisplayFrame.getInstance()。setVisible(false);
}

public void mouseDragged(MouseEvent e){
// TODO自动生成的方法存根
}

public void mouseMoved MouseEvent e){
System.out.println(Mouse moved+ e.getX()+x+ e.getY());
DisplayFrame.showDisplay(e.getX(),e.​​getY());
}
}

private static MainFrame mainFrame;

public static MainFrame getInstance(){
if(mainFrame == null){
mainFrame = new MainFrame();
mainFrame.setLayout(new GridBagLayout());

JPanel blocker = new JPanel();
blocker.setBackground(Color.RED);
blocker.setPreferredSize(new Dimension(200,200));
MouseAdapter ma = new MouseAdapter(){
};
blocker.addMouseListener(ma);
blocker.addMouseMotionListener(ma);
mainFrame.add(blocker);

尺寸尺寸=新尺寸(900,700);
mainFrame.setPreferredSize(size);
mainFrame.setMinimumSize(size);
}

return mainFrame;
}

public static void main(String args []){
EventQueue.invokeLater(new Runnable(){
@Override
public void run (){
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch(ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex){
ex.printStackTrace() ;
}

JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(getInstance(),BorderLayout.CENTER);
frame.pack();

frame.setVisible(true);
}
});
}

static class DisplayFrame extends JFrame {

public static DisplayFrame display;

DisplayFrame(){
setUndecorated(true);
JPanel panel1 = new JPanel();
panel1.setBackground(Color.BLACK);
JPanel panel2 = new JPanel();
panel2.setBackground(Color.WHITE);
JTabbedPane tPane = new JTabbedPane();
tane.setTabPlacement(JTabbedPane.BOTTOM);
tPane.addTab(Black,panel1);
tPane.addTab(White,panel2);
add(tPane);
}

public static DisplayFrame getInstance(){
if(display == null){
display = new DisplayFrame();
}

//设置大小
尺寸大小=新尺寸(200,200);
display.setPreferredSize(size);
display.setMinimumSize(size);
display.setMaximumSize(size);

返回显示;
}

public static void showDisplay(int x,int y){
getInstance();

int compX =(int)MainFrame.getInstance()。getLocationOnScreen()。getX();
int compY =(int)MainFrame.getInstance()。getLocationOnScreen()。getY();
//应该是位于右边的10个像素,光标下方的20个像素
int newX = compX + x + 10;
int newY = compY + y + 20;

//设置位置
display.setLocation(newX,newY);

if(!display.isVisible()){
display.setVisible(true);
}
//这是为了确保框架没有隐藏在主窗口后面
display.toFront();

} // end method
}
}


The software I am working with is written in Java. This particular problem only manifests on Mac, the program functions properly on Windows and Linux.

I basically wrote a custom "tooltip" that follows the mouse around the main window of the application. It is actually a separate, undecorated frame (we will call the "display frame") that changes location based off of mouseMoved events that are received by the window the cursor is moving over. The default location is slightly below and to the right of the cursor, but when it reaches edges of the window it can "flip" to the left side or the top side of the cursor. This works properly on other platforms, as mentioned before, but it appears on the mac that this mouseMoved event is somehow consumed by the display frame, before it ever gets to the main application. So that window is never receiving mouseMoved events, therefore never moving and following the cursor. The only time the display frame changes location, is if the cursor enters it. Then, the main window triggers a mouseExited event, which causes the display frame to setVisible(false) (I don't want to show the display frame if the cursor isn't in the main window). This then triggers a mouseEntered event, which causes the display frame to be redrawn below and to the right, as it is supposed to be.

I have tried setting the focus to the main window when the redraw method is called, and I have printed out .hasFocus() once this is done, and the other window now has focus, but is still not receiving mouseMoved events. Also, putting a mouse listener on the display frame does not work because the mouseMoved events I am interested in are not within the actual frame of the displayFrame, so those are never triggered either.

The very strange part, is there is a way to produce the proper behavior on the mac. Having the display frame follow the mouse around is a certain "Tool Mode" that can be selected within the application. While in this mode the user can also add additional features to the main window. If the user left clicks while in this mode, a small dialog pops up asking you to name the new feature, if you do so and click "Okay", or don't and click "Cancel", now the display frame will follow the mouse around. You can break it again if you move too quickly and manage to get the cursor inside the display frame before it can redraw, and then you're back to square one where it won't follow you around.

The dialog box requires a parent to be set when it is shown, and we thought perhaps it was setting the main window as its parent and that somehow when it came and then left, the mouse events were then passed on to the parent. But, the dialog box is setting its parent to the display frame. So that is sadly not the case either.

This problem occurs on various versions of osx and on different versions of Java. For reference I am running 10.9.2, but it has been replicated on 10.9.3, 10.9.4, and 10.8, 10.6. I am running Java 1.7.0_51 and 1.7.0_67.

I have spent some time looking online and haven't come up with anything that has really helped and would appreciate any help from here. Below is a much simpler sample program that I wrote that replicates the problem I am experiencing.

Thanks. package mouseMovedProblem;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.event.MouseInputListener;

public class MainFrame extends JPanel{
    public static MainFrame mainFrame;

    MainFrame(){
//      setOpaque(false);
        setBackground(Color.WHITE);
        MouseListener ml = new MouseListener();
        addMouseListener(ml);
        addMouseMotionListener(ml);
    }

    private class MouseListener implements MouseInputListener{
        public void mouseClicked(MouseEvent e) {
//          System.out.println("Mouse clicked");
            DisplayFrame.showDisplay(e.getX(), e.getY());
            String test = JOptionPane.showInputDialog(DisplayFrame.getInstance(), 
                    "This is a test","test");
        }
        public void mousePressed(MouseEvent e) {
//          DisplayFrame.showDisplay(e.getX(), e.getY());
        }
        public void mouseReleased(MouseEvent e) {
//          DisplayFrame.showDisplay(e.getX(), e.getY());
        }
        public void mouseEntered(MouseEvent e) {
//          DisplayFrame.showDisplay(e.getX(), e.getY());
        }
        public void mouseExited(MouseEvent e) {
            DisplayFrame.getInstance().setVisible(false);
        }
        public void mouseDragged(MouseEvent e) {
            // TODO Auto-generated method stub
        }
        public void mouseMoved(MouseEvent e) {
//          System.out.println("Mouse moved");
            DisplayFrame.showDisplay(e.getX(), e.getY());
        }
    }

    public static MainFrame getInstance(){
        if(mainFrame == null){
            mainFrame = new MainFrame();
        }
        Dimension size = new Dimension(900,700);
        mainFrame.setPreferredSize(size);
        mainFrame.setMinimumSize(size);

        return mainFrame;
    }

    public static void main(String args[]){
        JFrame frame = new JFrame();
        frame.setLayout(new BorderLayout());
        frame.add(getInstance(), BorderLayout.CENTER);
        frame.pack();

        frame.setVisible(true);
    }

}

class DisplayFrame extends JFrame{
    public static DisplayFrame display;

    DisplayFrame(){
        setUndecorated(true);
        JPanel panel1 = new JPanel();
        panel1.setBackground(Color.BLACK);
        JPanel panel2 = new JPanel();
        panel2.setBackground(Color.WHITE);
        JTabbedPane tPane = new JTabbedPane();
        tPane.setTabPlacement(JTabbedPane.BOTTOM);
        tPane.addTab("Black", panel1);
        tPane.addTab("White", panel2);
        add(tPane);
    }

    public static DisplayFrame getInstance(){
        if(display == null){
            display = new DisplayFrame();
        }

        // Set size
        Dimension size = new Dimension(200,200);
        display.setPreferredSize(size);
        display.setMinimumSize(size);
        display.setMaximumSize(size);

        return display;
    }

    public static void showDisplay(int x, int y){
        getInstance();

        int compX = (int) MainFrame.getInstance().getLocationOnScreen().getX();
        int compY = (int) MainFrame.getInstance().getLocationOnScreen().getY();
    // Should be the location 10 pixels to the right and 20 pixels below the cursor             
        int newX = compX+x+10;
        int newY = compY+y+20;

    // Set location
        display.setLocation(newX, newY);

        if(!display.isVisible()){
            display.setVisible(true);
        }
    // This is to make sure the frame doesn't get hidden behind the main window     
        display.toFront(); 

    } // end method 
}

解决方案

Once I corrected your code so it would compile and run, I had no issues with your example...

MacOS X 10.9.4, Java 1.8.0_05.

If there are any other components on the screen which have a registered MouseListener or MouseMoitionListener, they will block events going through to parent components. There is a trick you can use to overcome this is issue, it's a little bit more work, but it does work.

Basically, you can register an AWTListener with the Toolkit masked to deliver MOUSE_MOTION_EVENT_MASK events. This are global, so you will receive ALL mouse motion events that go through the Event Queue, so you will need filter them appropriately, for example...

import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class MainFrame extends JPanel {

    MainFrame() {
//      setOpaque(false);
        setBackground(Color.WHITE);
        MouseListener ml = new MouseListener();
        addMouseListener(ml);
        addMouseMotionListener(ml);

        Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {

            @Override
            public void eventDispatched(AWTEvent event) {
                MouseEvent evt = (MouseEvent) event;
                Point p = evt.getPoint();
                if (evt.getSource() != MainFrame.this) {
                    p = SwingUtilities.convertPoint(evt.getComponent(), p, MainFrame.this);
                }
                if (MainFrame.this.getBounds().contains(p)) {
                    System.out.println(p.x + "x" + p.y);
                }
            }
        }, AWTEvent.MOUSE_MOTION_EVENT_MASK);
    }

    private class MouseListener extends MouseAdapter {

        public void mouseClicked(MouseEvent e) {
//          System.out.println("Mouse clicked");
            DisplayFrame.showDisplay(e.getX(), e.getY());
        }

        public void mousePressed(MouseEvent e) {
//          DisplayFrame.showDisplay(e.getX(), e.getY());
        }

        public void mouseReleased(MouseEvent e) {
//          DisplayFrame.showDisplay(e.getX(), e.getY());
        }

        public void mouseEntered(MouseEvent e) {
//          DisplayFrame.showDisplay(e.getX(), e.getY());
        }

        public void mouseExited(MouseEvent e) {
            DisplayFrame.getInstance().setVisible(false);
        }

        public void mouseDragged(MouseEvent e) {
            // TODO Auto-generated method stub
        }

        public void mouseMoved(MouseEvent e) {
            System.out.println("Mouse moved " + e.getX() + "x" + e.getY());
            DisplayFrame.showDisplay(e.getX(), e.getY());
        }
    }

    private static MainFrame mainFrame;

    public static MainFrame getInstance() {
        if (mainFrame == null) {
            mainFrame = new MainFrame();
            mainFrame.setLayout(new GridBagLayout());

            JPanel blocker = new JPanel();
            blocker.setBackground(Color.RED);
            blocker.setPreferredSize(new Dimension(200, 200));
            MouseAdapter ma = new MouseAdapter() {
            };
            blocker.addMouseListener(ma);
            blocker.addMouseMotionListener(ma);
            mainFrame.add(blocker);

            Dimension size = new Dimension(900, 700);
            mainFrame.setPreferredSize(size);
            mainFrame.setMinimumSize(size);
        }

        return mainFrame;
    }

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(getInstance(), BorderLayout.CENTER);
                frame.pack();

                frame.setVisible(true);
            }
        });
    }

    static class DisplayFrame extends JFrame {

        public static DisplayFrame display;

        DisplayFrame() {
            setUndecorated(true);
            JPanel panel1 = new JPanel();
            panel1.setBackground(Color.BLACK);
            JPanel panel2 = new JPanel();
            panel2.setBackground(Color.WHITE);
            JTabbedPane tPane = new JTabbedPane();
            tPane.setTabPlacement(JTabbedPane.BOTTOM);
            tPane.addTab("Black", panel1);
            tPane.addTab("White", panel2);
            add(tPane);
        }

        public static DisplayFrame getInstance() {
            if (display == null) {
                display = new DisplayFrame();
            }

            // Set size
            Dimension size = new Dimension(200, 200);
            display.setPreferredSize(size);
            display.setMinimumSize(size);
            display.setMaximumSize(size);

            return display;
        }

        public static void showDisplay(int x, int y) {
            getInstance();

            int compX = (int) MainFrame.getInstance().getLocationOnScreen().getX();
            int compY = (int) MainFrame.getInstance().getLocationOnScreen().getY();
            // Should be the location 10 pixels to the right and 20 pixels below the cursor             
            int newX = compX + x + 10;
            int newY = compY + y + 20;

            // Set location
            display.setLocation(newX, newY);

            if (!display.isVisible()) {
                display.setVisible(true);
            }
            // This is to make sure the frame doesn't get hidden behind the main window     
            display.toFront();

        } // end method 
    }
}

This example will print the x/y position of the mouse. You will see that when your MouseMoitionListener stops receiving events, the AWTListener containers to print out results.

Updated

I was able to test it using Java 1.7.0_15 and was able to replicate the issue. This seems to be a bug in the Java 7, as even the AWTListener stopped displaying output...

So what's the solution? Upgrade to Java 8...

Okay, if you can't do that, you can use a "hack" work around...basically, you start Thread or javax.swing.Timer which probes java.awt.MouseInfo for the java.awt.PointerInfo and make determinations about the location of the cursor on the screen, for example...

Timer timer = new Timer(40, new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        PointerInfo pi = MouseInfo.getPointerInfo();
        Point p = pi.getLocation();
        SwingUtilities.convertPointFromScreen(p, MainFrame.this);
        if (MainFrame.this.getBounds().contains(p)) {
            System.out.println("pi = " + p.x + "x" + p.y);
        }
    }
});
timer.start();

The important thing about this to:

  1. Make sure the mouse pointer is within the confines of your component and
  2. Make sure it has changed before you update anything

As an example...

import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class MainFrame extends JPanel {

    MainFrame() {
//      setOpaque(false);
        setBackground(Color.WHITE);
        MouseListener ml = new MouseListener();
        addMouseListener(ml);
        addMouseMotionListener(ml);

        Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {

            @Override
            public void eventDispatched(AWTEvent event) {
                MouseEvent evt = (MouseEvent) event;
                Point p = evt.getPoint();
                if (evt.getSource() != MainFrame.this) {
                    p = SwingUtilities.convertPoint(evt.getComponent(), p, MainFrame.this);
                }
                if (MainFrame.this.getBounds().contains(p)) {
                    System.out.println(p.x + "x" + p.y);
                }
            }
        }, AWTEvent.MOUSE_MOTION_EVENT_MASK);

        Timer timer = new Timer(40, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                PointerInfo pi = MouseInfo.getPointerInfo();
                Point p = pi.getLocation();
                SwingUtilities.convertPointFromScreen(p, MainFrame.this);
                if (MainFrame.this.getBounds().contains(p)) {
                    System.out.println("pi = " + p.x + "x" + p.y);
                }
            }
        });
        timer.start();
    }

    private class MouseListener extends MouseAdapter {

        public void mouseClicked(MouseEvent e) {
//          System.out.println("Mouse clicked");
            DisplayFrame.showDisplay(e.getX(), e.getY());
        }

        public void mousePressed(MouseEvent e) {
//          DisplayFrame.showDisplay(e.getX(), e.getY());
        }

        public void mouseReleased(MouseEvent e) {
//          DisplayFrame.showDisplay(e.getX(), e.getY());
        }

        public void mouseEntered(MouseEvent e) {
//          DisplayFrame.showDisplay(e.getX(), e.getY());
        }

        public void mouseExited(MouseEvent e) {
            DisplayFrame.getInstance().setVisible(false);
        }

        public void mouseDragged(MouseEvent e) {
            // TODO Auto-generated method stub
        }

        public void mouseMoved(MouseEvent e) {
            System.out.println("Mouse moved " + e.getX() + "x" + e.getY());
            DisplayFrame.showDisplay(e.getX(), e.getY());
        }
    }

    private static MainFrame mainFrame;

    public static MainFrame getInstance() {
        if (mainFrame == null) {
            mainFrame = new MainFrame();
            mainFrame.setLayout(new GridBagLayout());

            JPanel blocker = new JPanel();
            blocker.setBackground(Color.RED);
            blocker.setPreferredSize(new Dimension(200, 200));
            MouseAdapter ma = new MouseAdapter() {
            };
            blocker.addMouseListener(ma);
            blocker.addMouseMotionListener(ma);
            mainFrame.add(blocker);

            Dimension size = new Dimension(900, 700);
            mainFrame.setPreferredSize(size);
            mainFrame.setMinimumSize(size);
        }

        return mainFrame;
    }

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(getInstance(), BorderLayout.CENTER);
                frame.pack();

                frame.setVisible(true);
            }
        });
    }

    static class DisplayFrame extends JFrame {

        public static DisplayFrame display;

        DisplayFrame() {
            setUndecorated(true);
            JPanel panel1 = new JPanel();
            panel1.setBackground(Color.BLACK);
            JPanel panel2 = new JPanel();
            panel2.setBackground(Color.WHITE);
            JTabbedPane tPane = new JTabbedPane();
            tPane.setTabPlacement(JTabbedPane.BOTTOM);
            tPane.addTab("Black", panel1);
            tPane.addTab("White", panel2);
            add(tPane);
        }

        public static DisplayFrame getInstance() {
            if (display == null) {
                display = new DisplayFrame();
            }

            // Set size
            Dimension size = new Dimension(200, 200);
            display.setPreferredSize(size);
            display.setMinimumSize(size);
            display.setMaximumSize(size);

            return display;
        }

        public static void showDisplay(int x, int y) {
            getInstance();

            int compX = (int) MainFrame.getInstance().getLocationOnScreen().getX();
            int compY = (int) MainFrame.getInstance().getLocationOnScreen().getY();
            // Should be the location 10 pixels to the right and 20 pixels below the cursor             
            int newX = compX + x + 10;
            int newY = compY + y + 20;

            // Set location
            display.setLocation(newX, newY);

            if (!display.isVisible()) {
                display.setVisible(true);
            }
            // This is to make sure the frame doesn't get hidden behind the main window     
            display.toFront();

        } // end method 
    }
}

这篇关于Java Mouse事件未在OSX上注册的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆