简体   繁体   中英

Java stops capturing mouse movement events after maximizing or full screening a window in Mac OS X

When I enlarge a window by either pressing the maximize button or the full screen button on OS X, mouse movement events are no longer captured (though dragging is).

I have included a demo program below that highlights the issue. The maximization problem can be replicated using the MouseEventDemo web start example on the Java Tutorials website .

After some troubleshooting, I noted that mouse movements are recaptured if the mouse leaves the window (eg, moves to the top of the window to access the menu bar) and then returns. It seems the issue may have something to do with the relation between the mouse position and the window during resizing animations, since the mouse is not in the frame before the resizing, but is afterward even though it didn't necessarily move in the process.

import java.awt.Window;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.lang.reflect.Method;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class Main implements MouseMotionListener {

    JLabel label = new JLabel("label");

    public static void main(String[] args) {
        Main main = new Main();
        main.init();
    }

    public void init() {
        JFrame frame = new JFrame();
        frame.setSize(640, 480);
        frame.setLocationRelativeTo(null);
        frame.getContentPane().add(label);
        frame.addMouseMotionListener(this);
        frame.setVisible(true);

        if (isMacOSX()) {
            enableFullScreenMode(frame);
        }
    }

    public void mouseDragged(MouseEvent e) {
        label.setText(e.toString());
    }

    public void mouseMoved(MouseEvent e) {
        label.setText(e.toString());
    }

    private static boolean isMacOSX() {
        return System.getProperty("os.name").indexOf("Mac OS X") >= 0;
    }

    public static void enableFullScreenMode(Window window) {
        try {
            Class<?> clazz = Class.forName("com.apple.eawt.FullScreenUtilities");
            Method method = clazz.getMethod("setWindowCanFullScreen", new Class<?>[] { Window.class, boolean.class });
            method.invoke(null, window, true);
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

Running the code above should reveal when the label does and does not update.

I am running OS X Version 10.9 Build 13A3017 with Java SE 7 [1.7.0_45].

Empirically, the problem disappears if one switches away from and back to the application while maximized. Adding a ComponentListener that forces the frame toFront() seems to work. As an aside, Swing GUI objects should be constructed and manipulated only on the event dispatch thread .

frame.addComponentListener(new ComponentAdapter() {

    @Override
    public void componentResized(ComponentEvent e) {
        frame.toFront();
    }
});

As tested:

import java.awt.EventQueue;
import java.awt.Window;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.lang.reflect.Method;
import javax.swing.JFrame;
import javax.swing.JLabel;

/** @see http://stackoverflow.com/a/20054242/230513 */
public class Main implements MouseMotionListener {

    JLabel label = new JLabel("label");

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                Main main = new Main();
                main.init();
            }
        });
    }

    public void init() {
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(label);
        frame.pack();
        frame.setSize(640, 480);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        if (isMacOSX()) {
            enableFullScreenMode(frame);
        }
        frame.addMouseMotionListener(this);
        frame.addComponentListener(new ComponentAdapter() {

            @Override
            public void componentResized(ComponentEvent e) {
                frame.toFront();
            }
        });
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        label.setText(e.toString());
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        label.setText(e.toString());
    }

    private static boolean isMacOSX() {
        return System.getProperty("os.name").indexOf("Mac OS X") >= 0;
    }

    public static void enableFullScreenMode(Window window) {
        try {
            Class<?> clazz = Class.forName("com.apple.eawt.FullScreenUtilities");
            Method method = clazz.getMethod("setWindowCanFullScreen",
                    new Class<?>[]{Window.class, boolean.class});
            method.invoke(null, window, true);
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

Oracle回应我提交的错误报告 ,在他们的评论中指出应该在Java 8中解决该问题。上面的代码使用OS X 10.9.2在1.8.0 JRE(build 1.8.0-b132)上按预期工作。

I was able to find a work around to the maximized part of this issue by adding a windowStateListener to the frame and doing the following:

frame.addWindowStateListener(new WindowStateListener()
{
    @Override
    public void windowStateChanged(WindowEvent e)
    {
        if (Frame.MAXIMIZED_BOTH == e.getNewState())
        {
            frame.toBack();
            frame.toFront();
        }
    }
});

If you combine this with the resize work around from trashgod you should be in good shape.

The events mouseReleased, mouseClicked are not triggered when jdk 1.6.0_65 (yosemite) is use, for jdk 1.8.0_25 (yosemite) the events are triggered and also that events were triggered on jdk 1.6 (maverick). What might be the issue?

java -version java version "1.6.0_65" Java(TM) SE Runtime Environment (build 1.6.0_65-b14-466.1-11M4716) Java HotSpot(TM) 64-Bit Server VM (build 20.65-b04-466.1, mixed mode)

windowActivated windowOpened mousePressed windowClosing windowDeactivated

java version "1.8.0_25" Java(TM) SE Runtime Environment (build 1.8.0_25-b17) Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)

windowActivated windowOpened mousePressed mouseReleased mouseClicked windowClosing windowDeactivated

import java.awt. ; import java.awt.event. ;

public class TestMouseEventsOnYosemite {

public static void main(String[] args) {
    TestFrame testFrame = new TestFrame();
    testFrame.setVisible(true);
    testFrame.toFront();
}

public static class TestFrame extends Frame implements WindowListener {

    public TestFrame() {
        setLayout(null);
        addNotify();
        Button okButon = new Button("    Ok    ");
        add(okButon);

        okButon.addMouseListener(new MouseAdapter() {

            public void mouseReleased(MouseEvent event) {
                System.out.println("mouseReleased");
            }

            public void mousePressed(MouseEvent event) {
                System.out.println("mousePressed");
            }

            public void mouseClicked(MouseEvent event) {
                System.out.println("mouseClicked");
            }
        }
        );

        okButon.addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent event) {
                System.out.println("keyPressed");
            }
        }
        );

        int dy = okButon.getPreferredSize().height;

        okButon.setBounds(30, 50, 100, dy);

        setSize(150, 150);
        addWindowListener(this);
        setResizable(true);
        okButon.requestFocusInWindow();
    }

    public void windowActivated(WindowEvent e) {
        System.out.println("windowActivated");
    }

    public void windowClosed(WindowEvent e) {
        System.out.println("windowClosed");
    }

    public void windowDeactivated(WindowEvent e) {
        System.out.println("windowDeactivated");
    }

    public void windowDeiconified(WindowEvent e) {
        System.out.println("windowDeiconified");
    }

    public void windowIconified(WindowEvent e) {
        System.out.println("windowIconified");
    }

    public void windowOpened(WindowEvent e) {
        System.out.println("windowOpened");
    }

    public void windowClosing(WindowEvent e) {
        System.out.println("windowClosing");
    }
}

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM