Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/383.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
这是教Java框架了解Windows的Aero Snap功能的唯一方法吗?_Java_Swing_Jframe_Minimize_Aero Snap - Fatal编程技术网

这是教Java框架了解Windows的Aero Snap功能的唯一方法吗?

这是教Java框架了解Windows的Aero Snap功能的唯一方法吗?,java,swing,jframe,minimize,aero-snap,Java,Swing,Jframe,Minimize,Aero Snap,如果我通过单击Windows窗口装饰的最小化按钮来最小化屏幕左侧的JFrame,并通过Alt Tab键或单击Windows任务栏中的来取消其动画化,则该帧将被正确地还原到左侧。好! 但是如果我把帧最小化 setExtendedState( getExtendedState() | Frame.ICONIFIED ); 通过将鼠标悬停在Windows任务栏上查看预览,它会将框架显示在错误的位置。 通过按住Alt键或在Windows任务栏中单击来取消动画化框架后,框架将恢复到错误的位置和大小。帧边

如果我通过单击Windows窗口装饰的最小化按钮来最小化屏幕左侧的
JFrame
,并通过Alt Tab键或单击Windows任务栏中的来取消其动画化,则该帧将被正确地还原到左侧。好!

但是如果我把帧最小化

setExtendedState( getExtendedState() | Frame.ICONIFIED );
通过将鼠标悬停在Windows任务栏上查看预览,它会将框架显示在错误的位置。 通过按住Alt键或在Windows任务栏中单击来取消动画化框架后,框架将恢复到错误的位置和大小。帧边界是“unsnaped”值,如果将帧从屏幕边界拖开,Windows通常会记住恢复该值

错误的屏幕记录:

我的结论是,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提交了一个bug:

这似乎是一个Swing bug。错误数据库上的错误报告:

在本报告中,该错误无法复制,现在您遇到了相同的错误(我认为是相同的,或至少相关),也许是重新打开本报告的好时机。(我没有找到任何其他与此相关的参考,因此我认为它尚未修复)

有没有更好的方法让AeroSnap和Java框架协同工作?

也好不到哪里去。直接设置扩展状态会绕过操作系统设置扩展状态的处理方法

如果您查看
JFrame#setExtendedState
的源代码,就会发现它调用了
FramePeer
setState
方法。JDK的
JFrame
接口的
FramePeer
实现是
WFramePeer
类,它将其
setState
方法声明为
native
。所以,除非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.jar
jna 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
实例已加载。您可以在启动时加载它,以避免第一次延迟


值得称赞的是。

也许这些bug是相关的,但您发现的bug看起来更像附件中的屏幕截图。这是它的一部分。我的bug更多的是关于“通过编程最小化来释放快照状态”。哦,好吧,那么对不起。我想我的英语比我想象的差。谢谢你对WFramePeer的分析。不幸的是,你的“隐藏和显示帧”源代码只适用于快照帧状态。如果帧在最小化之前在屏幕的中间,它将总是被恢复到左上角。当正确地恢复一个被捕获的帧时,它会丢失之前的位置和大小(通常会在unnn啪啪上恢复)。@博恩沃德“如果帧在最小化之前在屏幕的中间,它总是会被恢复到左上角。”我没有得到这个行为。我的相框总是能正确地恢复(位置和大小)。@bobndrew显示相框后,您的具体操作步骤是什么?@bobndrew我试着用它玩了一会儿。预览位置太依赖于本机操作,我无法可靠地使其成为正确的操作。不过,我确实添加了一个本机代码解决方案。如果还没有,您应该将其作为JDK bug提交。注意:如果您使用
JFrame.ICONIFIED
而不是
Frame.ICONIFIED
等。您可以删除
Frame
导入。看起来这在JDK 9()中已修复。