【问题标题】:Java Swing - mouse pointer "shifted" on context menu when JFrame is maximizedJava Swing - 当JFrame最大化时,鼠标指针在上下文菜单上“移动”
【发布时间】:2012-05-13 15:28:16
【问题描述】:

在最大化 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 项目。

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

我在使用“右键单击上下文菜单”时观察到相同的行为,例如在 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

【问题讨论】:

  • 在我看来,这只是 Java 7 的一个错误,没有别的,尝试回到任何以前的版本,它不存在,Java 7 有很多错误,就像你刚才提到的那个:(

标签: linux swing java


【解决方案1】:

是的 - 这是@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)

【讨论】:

    【解决方案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();
            }
        }
    

    此代码 sn-p 基于workaround from the Netbeans developers

    【讨论】:

    • 如果桌面会话是 Gnome Shell 或 Mate 会话,它将当前 AWT 窗口管理器类设置为用于 Metacity WM 的类。
    • 好的。那么它为什么要检查 OTHER_WM 的值呢?
    【解决方案3】:

    我想补充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);
    

    【讨论】:

      猜你喜欢
      • 2019-08-08
      • 1970-01-01
      • 2020-07-17
      • 1970-01-01
      • 1970-01-01
      • 2016-01-18
      • 2011-07-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多