Java Swing - 当JFrame最大化时,鼠标指针在上下文菜单上“移位”

时间:2012-05-13 15:28:17

标签: linux swing java

我在最大化JFrame时遇到了一个处理鼠标位置的奇怪行为:

当我执行这个非常简单的代码时......

public class Test {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();

                JMenuBar menubar = new JMenuBar();
                JMenu menu = new JMenu("File");
                menu.add(new JMenuItem("New"));
                menubar.add(menu);
                frame.setJMenuBar(menubar);

                frame.setSize(200, 200);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}

...我通常可以点击File(首次点击 - 按,发布) - > New(第二次点击)。但是当我最大化JFrame并单击File时 - 上下文菜单会立即在鼠标释放时消失。 此外,当我按住鼠标按钮 - 为了防止消失 - 我必须进一步移动鼠标以关注New项目。

mouse shift

红点表示按下New并按住鼠标按钮后我必须移动鼠标以对焦File的区域(或多或少)。

我在使用“右键单击上下文菜单”时观察到相同的行为,例如右键单击JFreeChart中的图表时。

我认为这是JDK问题,因为我使用的是Oracle的JDK,但在安装OpenJDK后我得到了相同的结果。

有人观察到这种奇怪的行为吗?或者我错过了一些明显的东西?

我用:

  • 1.7.0_147-icedtea(或java-7-oracle的1.7.0_04)
  • OpenJDK运行时环境(IcedTea7 2.0)(7~b147-2.0-0ubuntu0.11.10.1)
  • OpenJDK 64位服务器VM(版本21.0-b17,混合模式)
  • Linux Mint 12(lisa)GNOME 3.2.1

3 个答案:

答案 0 :(得分:3)

是的 - 这是JDK7中的一个错误,如@nIcE cOw所述。

我已经安装了JDK6,但我无法重现这个错误。

java version "1.6.0_23"
OpenJDK Runtime Environment (IcedTea6 1.11pre) (6b23~pre11-0ubuntu1.11.10.2)
OpenJDK 64-Bit Server VM (build 20.0-b11, mixed mode)

答案 1 :(得分:2)

当需要使用Oracle Java 7时(例如,使用JavaFX时),还有一种解决方法。只需将以下代码行添加到窗口/框架类中:

        if (Arrays.asList("gnome-shell", "mate", "other...").contains(System.getenv("DESKTOP_SESSION"))) {
        try {
            Class<?> xwm = Class.forName("sun.awt.X11.XWM");
            Field awt_wmgr = xwm.getDeclaredField("awt_wmgr");
            awt_wmgr.setAccessible(true);
            Field other_wm = xwm.getDeclaredField("OTHER_WM");
            other_wm.setAccessible(true);
            if (awt_wmgr.get(null).equals(other_wm.get(null))) {
                Field metacity_wm = xwm.getDeclaredField("METACITY_WM");
                metacity_wm.setAccessible(true);
                awt_wmgr.set(null, metacity_wm.get(null));
            }
        }
        catch (Exception x) {
            x.printStackTrace();
        }
    }

此代码段基于workaround from the Netbeans developers

答案 2 :(得分:0)

我想补充problemzebra给出的解决方案。

因为在Linux上使用任何swing应用程序(使用Cinnamon桌面),即使在Java 6(更新45)上,它仍然适用于我

每次移动窗口或调整窗口大小时,问题都会重新出现,因此每次窗口更改时都需要重新应用解决方法。我创建了以下类,并在创建新窗口时使用它:

class LinuxWindowFix implements WindowStateListener {

    private final String desktop;
    private Field metacity_wm;
    private Field awt_wmgr;
    private boolean applyFix;

    private static LinuxWindowFix instance = new LinuxWindowFix();

    public static LinuxWindowFix getInstance() {
        return instance;
    }

    private LinuxWindowFix() {
        applyFix = false;

        List<String> linuxDesktops = Arrays.asList("gnome-shell", "mate", "cinnamon"); //add more desktop names here.

        desktop = System.getenv("DESKTOP_SESSION");
        if (desktop != null && linuxDesktops.contains(desktop.toLowerCase())) {
            try {
                Class<?> xwm = Class.forName("sun.awt.X11.XWM");
                awt_wmgr = xwm.getDeclaredField("awt_wmgr");
                awt_wmgr.setAccessible(true);
                Field other_wm = xwm.getDeclaredField("OTHER_WM");
                other_wm.setAccessible(true);
                if (awt_wmgr.get(null).equals(other_wm.get(null))) {
                    metacity_wm = xwm.getDeclaredField("METACITY_WM");
                    metacity_wm.setAccessible(true);
                    applyFix = true;
                }
            } catch (Exception ex) {
                //ignore
            }
        }
    }

    @Override
    public void windowStateChanged(WindowEvent e) {
        try {
            awt_wmgr.set(null, metacity_wm.get(null));
        } catch (Exception ex) {
            //ignore
        }
    }

    public void apply(Window w) {
        if (!applyFix) {
            return;
        }
        w.removeWindowStateListener(this);
        w.addWindowStateListener(this);
    }
}

只需为您创建的每个窗口调用此窗口,它就会按预期工作。

LinuxWindowFix.getInstance().apply(myWindow);