2016-01-06 3 views
28

Windows WindowDecorationの最小化ボタンをクリックし、Alt-Tabbingでウィンドウを最小化するかWindowsタスクバーでクリックを最小化することで、画面の左側にAero-SnappedしたJFrameを最小化すると、フレームが正しくスナップされます左に。良い!これは、WindowsのAero Snap機能についてJava Frameを教える唯一の方法ですか?

しかし、私は

setExtendedState(getExtendedState() | Frame.ICONIFIED); 

によってフレームを最小化してWindowsのタスクバー上にマウスを移動することにより、プレビューを見れば、それはフレーム間違った位置を示しています。 Alt-Tabbingでウィンドウを最小化した後、またはWindowsのTaskBarでクリックした後、フレームが間違った位置とサイズで復元されます。フレーム境界は、ウィンドウをScreenBorderから離してドラッグすると復元されることをWindowsが通常記憶している「スナップされていない」値です。バグの

画面録画:

enter image description here

私の結論は、JavaがAeroSnapについて知らないこと、であり、Windowsに間違った境界を提供します。

これはバグのための私の修正である(例えばToolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_VERT)); falseを返す):

import java.awt.Dimension; 
import java.awt.FlowLayout; 
import java.awt.Frame; 
import java.awt.Point; 
import java.awt.event.ActionListener; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.SwingUtilities; 

/** 
* Fix for the "Frame does not know the AeroSnap feature of Windows"-Bug. 
* 
* @author bobndrew 20160106 
*/ 
public class SwingFrameStateWindowsAeroSnapBug extends JFrame 
{ 
    Point  location = null; 
    Dimension size  = null; 


    public SwingFrameStateWindowsAeroSnapBug(final String title) 
    { 
    super(title); 
    initUI(); 
    } 

    private void initUI() 
    { 
    setDefaultCloseOperation(EXIT_ON_CLOSE); 
    setLayout(new FlowLayout()); 
    final JButton minimize = new JButton("Minimize"); 
    final JButton maximize = new JButton("Maximize"); 
    final JButton normal = new JButton("Normal"); 
    add(normal); 
    add(minimize); 
    add(maximize); 
    pack(); 
    setSize(200, 200); 


    final ActionListener listener = actionEvent -> 
    { 
     if (actionEvent.getSource() == normal) 
     { 
     setExtendedState(Frame.NORMAL); 
     } 
     else if (actionEvent.getSource() == minimize) 
     { 
     //Size and Location have to be saved here, before the minimizing of an AeroSnapped WindowsWindow leads to wrong values: 
     location = getLocation(); 
     size = getSize(); 
     System.out.println("saving location (before iconify) " + size + " and " + location); 

     setExtendedState(getExtendedState() | Frame.ICONIFIED);//used "getExtendedState() |" to preserve the MAXIMIZED_BOTH state 

     //does not fix the bug; needs a Window-Drag after DeMinimzing before the size is applied: 
     //   setSize(size); 
     //   setLocation(location); 
     } 
     else if (actionEvent.getSource() == maximize) 
     { 
     setExtendedState(getExtendedState() | Frame.MAXIMIZED_BOTH); 
     } 
    }; 

    minimize.addActionListener(listener); 
    maximize.addActionListener(listener); 
    normal.addActionListener(listener); 

    addWindowStateListener(windowEvent -> 
    { 
     System.out.println("oldState=" + windowEvent.getOldState() + " newState=" + windowEvent.getNewState()); 

     if (size != null && location != null) 
     { 
     if (windowEvent.getOldState() == Frame.ICONIFIED) 
     { 
      System.out.println("Fixing (possibly) wrong size and location on de-iconifying to " + size + " and " + location + "\n"); 
      setSize(size); 
      setLocation(location); 

      //Size and Location should only be applied once. Set NULL to avoid a wrong DeMinimizing of a following Windows-Decoration-Button-Minimize! 
      size = null; 
      location = null; 
     } 
     else if (windowEvent.getOldState() == (Frame.ICONIFIED | Frame.MAXIMIZED_BOTH)) 
     { 
      System.out.println("Set size and location to NULL (old values: " + size + " and " + location + ")"); 
      //Size and Location does not have to be applied, Java can handle the MAXIMIZED_BOTH state. Set NULL to avoid a wrong DeMinimizing of a following Windows-Decoration-Button-Minimize! 
      size = null; 
      location = null; 
     } 
     } 

    }); 
    } 


    public static void main(final String[] args) 
    { 
    SwingUtilities.invokeLater(new Runnable() 
    { 
     @Override 
     public void run() 
     { 
     new SwingFrameStateWindowsAeroSnapBug("AeroSnap and the Frame State").setVisible(true); 
     } 
    }); 
    } 
} 

これは、のWindows7の下にあるすべての状況で動作しているようですが、それはあまりにも多くのウィンドウ管理いじりのように感じています。何らかの理由でこれをLinuxやMacOSでテストすることは避けました;-)

AeroSnapとJavaフレームを連携させるより良い方法はありますか?


編集:

私は、Oracleのバグを提出しました:http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8147840

+1

まだ存在しない場合は、JDKバグとして提出する必要があります。 – user1803551

+1

ちょっとした注意: 'Frame.ICONIFIED'の代わりに' JFrame.ICONIFIED'を使うと 'Frame'インポートを削除できます。 – user1803551

+1

これはJDK 9(http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8037575)で修正されたようです。 – user1803551

答えて

6

はAeroSnapとJavaフレームは一緒に仕事しましょうためのより良い方法はあります(私はこれまで、他の参照を見つけることができませんでしたので、私はそれが修正されてhasn'tと仮定しますか)?

あまり良くありません。拡張状態を直接設定することは、OSが設定する処理をバイパスします。

JFrame#setExtendedStateのソースコードを見ると、FramePeersetStateメソッドが呼び出されます。 FramePeerインターフェイスのJDKのJFrame実装はクラスであり、setStateメソッドをと宣言しています。したがって、Oracleが何かを行うまで、またはネイティブ・コードを使用するまでは、あなたは不運です(下記参照)。

幸いにも、イベントリスナーとキャッシュ境界でナットする必要はありません。

:フレームの内容の詳細なプレビューを与えていないの副作用を持っていないこのものの

public class AeroResize extends JFrame { 

    public AeroResize(final String title) { 

     super(title); 
     initUI(); 
    } 

    private void initUI() { 

     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     setLayout(new FlowLayout()); 
     final JButton minimize = new JButton("Minimize"); 
     final JButton maximize = new JButton("Maximize"); 
     final JButton normal = new JButton("Normal"); 
     add(normal); 
     add(minimize); 
     add(maximize); 
     pack(); 

     minimize.addActionListener(e -> { 
      setVisible(false); 
      setExtendedState(getExtendedState() | JFrame.ICONIFIED); 
      setVisible(true); 
//   setLocation(getLocationOnScreen()); // Needed only for the preview. See comments section below. 
     }); 
    } 

    public static void main(final String[] args) { 

     SwingUtilities.invokeLater(() -> new AeroResize("AeroSnap and the Frame State").setVisible(true)); 
    } 
} 

:非表示とフレームを示すことは、それが最小化する前にあったものにサイズを「リセット」するのに十分ですあなたがJNAを使用することを気にしたい場合は、ネイティブコード

を使用して

enter image description here

ソリューションは、あなたは完全にネイティブプラットフォームの最小化を模倣することができます。ビルドパスにjna.jarjna-platform.jarを含める必要があります。

import java.awt.FlowLayout; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.SwingUtilities; 

import com.sun.jna.Native; 
import com.sun.jna.platform.win32.User32; 
import com.sun.jna.platform.win32.WinDef.HWND; 

public class AeroResize extends JFrame { 

    public AeroResize(final String title) { 

     super(title); 
     initUI(); 
    } 

    private void initUI() { 

     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     setLayout(new FlowLayout()); 
     final JButton minimize = new JButton("Minimize"); 
     final JButton maximize = new JButton("Maximize"); 
     final JButton normal = new JButton("Normal"); 
     add(normal); 
     add(minimize); 
     add(maximize); 
     pack(); 

     minimize.addActionListener(e -> { 
      HWND windowHandle = new HWND(Native.getComponentPointer(AeroResize.this)); 
      User32.INSTANCE.CloseWindow(windowHandle); 
     }); 
    } 

    public static void main(final String[] args) { 

     SwingUtilities.invokeLater(() -> new AeroResize("AeroSnap and the Frame State").setVisible(true)); 
    } 
} 

これはかなり説明的です。ウィンドウへのポインタを取得し、ネイティブのCloseWindow(実際には最小化して、図に行く)を使用します。 User32インスタンスがロードされているため、ボタンを押したときに最小限の遅延が発生することに注意してください。この最初の遅延を避けるために起動時にロードすることができます。

クレジットはthe accepted answer hereになります。

+0

あなたの 'WFramePeer'の分析に感謝します。 – bobndrew

+0

残念ながら、「フレームを隠して表示する」-sourcecodeは、スナップされたFrame-stateに対してのみ機能します。フレームが最小化する前に画面の中央にある場合、フレームは常に左上隅に復元されます。スナップされたフレームを正しく復元している間は、以前にスナップされた位置とサイズが失われます(通常、スナップされていない場合に復元されます)。 – bobndrew

+0

@bobndrew "*フレームが最小化する前に画面の中央にある場合、フレームは常に左上に復元されます。*"私はこの動作をしません。私のフレームは常に正しく復元されます(位置とサイズ)。 – user1803551

0

これは、Swingのバグのようです。バグデータベースにバグレポート:

JDK-7029238 : componentResized not called when the form is snapped

このレポートではバグは、あなたが同じバグ(私はそれは同じだと思う、あるいは少なくとも関連)、多分それはあるに遭遇した今、再現することができませんでしたこのレポートを再度開くのに良い時期です。

+1

バグは関係しているかもしれませんが、あなたが見つけたものは[JDK-8016356](https://bugs.openjdk.java.net/browse/JDK-8016356)に添付されているスクリーンショットのように見えます。それは[ビデオ](https://www.youtube.com/watch?v=-nZEh6Oo7Q8)です。私のバグは、 "プログラムで最小化することでスナップ状態を失う" _ともっと関係しています。 – bobndrew

+0

ああ、申し訳ありません。私の英語は思ったより悪いと思う。 – Tuzane

+0

問題ありません、あなたの助けをありがとう! – bobndrew

関連する問題