4

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

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

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项目。

鼠标移位

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

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

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

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

我用:

  • 1.7.0_147-icedtea(或 1.7.0_04 用于 java-7-oracle)
  • 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
4

3 回答 3

3

是的 - 这是@nIcE cOw 提到的 JDK7 中的一个错误。

我已经安装了 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)
于 2012-06-01T06:06:44.810 回答
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();
        }
    }

此代码片段基于Netbeans 开发人员的解决方法

于 2012-09-07T12:42:10.337 回答
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);
于 2014-08-27T23:41:39.287 回答