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(2 回目のクリック) をクリックできます。しかし、JFrame を最大化してクリックするとFile、マウスを離すとすぐにコンテキスト メニューが消えます。Newさらに、マウス ボタンを押したままにすると (消失を防ぐために)、アイテムにフォーカスするにはマウスをさらに動かさなければなりません。

マウスシフト

New赤い点は、マウス ボタンを押したままにしてフォーカスするためにマウスを移動する必要がある領域 (多かれ少なかれ) を表しFileます。

JFreeChart のチャートを右クリックするときなど、「右クリック コンテキスト メニュー」を使用するときに同じ動作を観察しました。

OracleのJDKを使っていたので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 (リサ) 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 によって与えられた解決策を補足したいと思います。

Java 6(アップデート45)でも、Linux(Cinnamonデスクトップを使用)のswingアプリケーションでまだ発生します

ウィンドウを移動またはサイズ変更するたびに問題が再発するため、ウィンドウが変更されるたびに回避策を再適用する必要があります。次のクラスを作成し、新しいウィンドウを作成するたびに使用します。

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 に答える