简体   繁体   English

这是教授Java框架有关Windows的Aero Snap功能的唯一方法吗?

[英]Is this the only way to teach a Java Frame something about the Aero Snap feature of Windows?

If I minimize a JFrame which was Aero-snapped to the left of the screen by clicking on the minimize-button of the Windows WindowDecoration and unminimize it by Alt-Tabbing or clicking it in the Windows TaskBar, the frame gets restored correctly snapped to the left. 如果我通过单击Windows WindowDecoration的最小化按钮并通过Alt-Tabbing最小化它或在Windows任务栏中单击它来最小化Aero捕捉到屏幕左侧的JFrame ,框架将恢复正确地捕捉到剩下。 Good! 好!

But if I minimize the frame by 但是,如果我最小化帧

setExtendedState( getExtendedState() | Frame.ICONIFIED );

and look at the preview by hovering over the Windows TaskBar, it shows the frame a wrong position. 并通过将鼠标悬停在Windows TaskBar上来查看预览,它会将框架显示错误的位置。 After unminimizing it by Alt-Tabbing or clicking it in the Windows TaskBar, the frame gets restored at this wrong position and size. 通过Alt-Tabbing取消最小化或在Windows任务栏中单击它后,框架将在此错误的位置和大小恢复。 The frame-bounds are the "unsnapped" values, which Windows normally remembers to restore if you drag the frame away from the ScreenBorder. 帧边界是“未绑定”值,如果您将帧拖离ScreenBorder,Windows通常会记住恢复该值。

A screen recording of the Bug: Bug的屏幕录制:

在此输入图像描述

My conclusion is, that Java does not know about AeroSnap and delivers the wrong bounds to Windows. 我的结论是,Java不了解AeroSnap并向Windows提供了错误的界限。 (For example Toolkit.getDefaultToolkit().isFrameStateSupported( Frame.MAXIMIZED_VERT ) ); (例如Toolkit.getDefaultToolkit().isFrameStateSupported( Frame.MAXIMIZED_VERT ) ); returns false.) 返回false。)

This is my fix for the bug: 这是我对bug的修复:

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 );
      }
    } );
  }
}

This seems to work for all situations under Windows7, but it feels like too much messing around with the window-management. 这似乎适用于Windows7下的所有情况,但感觉太乱用窗口管理了。 And I avoided to test this under Linux or MacOS for some reason ;-) 我出于某种原因避免在Linux或MacOS下测试这个;-)

Is there a better way to let AeroSnap and Java Frames work together? 是否有更好的方法让AeroSnap和Java Frames协同工作?


Edit: 编辑:

I've filed a bug at Oracle: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8147840 我在Oracle上提交了一个错误: http//bugs.java.com/bugdatabase/view_bug.do?bug_id=8147840

Is there a better way to let AeroSnap and Java Frames work together? 是否有更好的方法让AeroSnap和Java Frames协同工作?

Not much better. 好多了。 Directly setting the extended state bypasses the OS's treatment of setting it. 直接设置扩展状态会绕过操作系统设置它的处理。

If you take a look at the source code of JFrame#setExtendedState you will see that it calls the FramePeer 's setState method. 如果你看一下JFrame#setExtendedState的源代码,你会看到它调用了FramePeersetState方法。 The JDK's JFrame implementation of the FramePeer interface is the WFramePeer class, which declares its setState method as native . JDK的FramePeer接口的JFrame实现是WFramePeer类,它将setState方法声明为native So, you're out of luck until Oracle does something about it or you use native code (see below). 因此,在Oracle对此做一些事情或使用本机代码之前,你运气不好(见下文)。

Fortunately, you don't necessarily have to go nuts with event listeners and caching bounds. 幸运的是,您不必为事件监听器和缓存边界而疯狂。 Hiding and showing the frame is enough to "reset" the size to what it was before the minimization: 隐藏和显示框架足以将大小“重置”为最小化之前的大小:

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));
    }
}

Though this does have a side-effect of not giving a detailed preview of the frame's contents: 虽然这确实有副作用,没有给出框架内容的详细预览:

在此输入图像描述

Solution using native code 解决方案使用本机代码

If you'd care to use JNA , then you can completely mimic the native platform's minimization. 如果您想使用JNA ,那么您可以完全模仿本机平台的最小化。 You'll need to include jna.jar and jna-platform.jar in your build path. 您需要在构建路径中包含jna.jarjna.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));
    }
}

It's pretty self explanatory. 这是非常自我解释的。 You get a pointer to the window and use the native CloseWindow (which actually minimizes, go figure) on it. 你得到一个指向窗口的指针,并使用本机CloseWindow (实际上最小化,去图)。 Note that the minimalistic way I wrote it will cause a small delay the first time the button is pressed because the User32 instance is loaded. 请注意,我编写它的简约方法会在第一次按下按钮时导致一个小延迟,因为User32实例已加载。 You can load it on startup to avoid this first-time delay. 您可以在启动时加载它以避免第一次延迟。

Credit goes to the accepted answer here . 信用证转到这里接受的答案

This seems to be a Swing bug. 这似乎是一个Swing bug。 The bug report on the Bug Database: 关于Bug数据库的错误报告:

JDK-7029238 : componentResized not called when the form is snapped JDK-7029238:在捕捉表单时未调用componentResized

In this report the bug could not be reproduced, now you encountered the same bug (I think it is the same, or related at least), maybe it is a good time to re-open this report. 在这个报告中,错误无法再现,现在您遇到了相同的错误(我认为它是相同的,或至少相关),也许是重新打开此报告的好时机。 (I did not find any other reference to this, so I assume it hasn´t been fixed) (我没有找到任何其他参考,所以我认为它没有被修复)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Windows Snap功能可用于未修饰的窗口? - Windows Snap feature for undecorated windows? Java Desktop App中的Windows 7 Aero概览 - Windows 7 Aero Peek of Tabs in Java Desktop App 使用自定义标题栏管理Windows Aero摇动功能 - Manage Windows Aero shake feature with custom title bar 对矩形进行编码(Java) - Coding something about a rectangle (Java) 有没有办法让Java线程仅在初始化时才做某事? - Is there a way to get a Java thread to do something only upon initialization? 有没有办法从Windows或Linux机器上远程安装程序以编程到Windows机器? 最好是一些容易用Java编写的代码 - Is there a way to remotely install to program to a windows machine from both a windows or a linux machine? Preferably something easy to code in java 有没有办法在 Android Studio 中教 java-> kotlin 转换器在转换 findViewById 时不使用 `as` 运算符? - Is there way to teach java-> kotlin converter in Android Studio to not use `as` operator when converting findViewById? 任何以我学习java(命令行,没有intelliSense或VS)的方式教授C#的教程或书籍? - Any tutorials or books that teach C# the way I learned java (commandline, without intelliSense or VS)? 关于java.util.InputMismatchException的东西吗? - Something about java.util.InputMismatchException? 有关Java中套接字和多线程的一些知识 - Something to know about socket and multithreading in java
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM