setlayout - ¿Es esta la única forma de enseñarle a Java Frame algo sobre la función Aero Snap de Windows?
swing windows java (2)
Si JFrame
un JFrame
que fue Aero-snapped a la izquierda de la pantalla haciendo clic en el botón Minimizar de Windows WindowDecoration y lo minimizo mediante Alt-Tabbing o haciendo clic en él en la barra de tareas de Windows, el cuadro se restaura correctamente ajustado al izquierda. ¡Bueno!
Pero si minimizo el cuadro por
setExtendedState( getExtendedState() | Frame.ICONIFIED );
y mire la vista previa colocando el cursor sobre la Barra de tareas de Windows, muestra el marco en una posición incorrecta. Después de minimalizarlo mediante Alt-Tabbing o hacer clic en él en la Barra de tareas de Windows, el marco se restaura en esta posición y tamaño incorrectos. Los límites de marco son los valores "sin seccionar", que Windows normalmente recuerda restaurar si arrastra el marco fuera de ScreenBorder.
Una grabación de pantalla del error:
Mi conclusión es que Java no conoce AeroSnap y entrega los límites incorrectos a Windows. (Por ejemplo, Toolkit.getDefaultToolkit().isFrameStateSupported( Frame.MAXIMIZED_VERT ) );
devuelve falso.)
Esta es mi solución para el error:
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 );
}
} );
}
}
Esto parece funcionar para todas las situaciones en Windows 7, pero se siente como un lío con la administración de ventanas. Y evité probar esto bajo Linux o MacOS por alguna razón ;-)
¿Hay una mejor manera de permitir que AeroSnap y Java Frames trabajen juntos?
Editar:
He archivado un error en Oracle: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8147840
¿Hay una mejor manera de permitir que AeroSnap y Java Frames trabajen juntos?
No mucho mejor La configuración directa del estado extendido evita el tratamiento del OS para configurarlo.
Si JFrame#setExtendedState
un vistazo al código fuente de JFrame#setExtendedState
, verás que llama al método setState
. La implementación JFrame
del JDK de la interfaz FramePeer
es la clase WFramePeer
, que declara su método setState
como native
. Por lo tanto, no tiene suerte hasta que Oracle haga algo al respecto o use un código nativo (consulte a continuación).
Afortunadamente, no necesariamente tiene que volverse loco con los detectores de eventos y los límites de almacenamiento en caché. Ocultar y mostrar el marco es suficiente para "restablecer" el tamaño a lo que era antes de la minimización:
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));
}
}
Aunque esto tiene un efecto secundario de no dar una vista previa detallada de los contenidos del marco:
Solución usando código nativo
Si desea utilizar JNA , puede imitar por completo la minimización de la plataforma nativa. Deberá incluir jna.jar
y jna-platform.jar
en su ruta de compilación.
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));
}
}
Es bastante auto explicativo. CloseWindow
un puntero a la ventana y usas CloseWindow
nativo (que en realidad minimiza, CloseWindow
) en él. Tenga en cuenta que la forma minimalista en que lo escribí provocará un pequeño retraso la primera vez que se presiona el botón porque la instancia de User32
está cargada. Puede cargarlo al inicio para evitar este primer retraso.
El crédito va a la respuesta aceptada aquí .
Esto parece ser un error de Swing. El informe de error en la base de datos de errores:
JDK-7029238: componentResized no se llama cuando se forma el formulario
En este informe, no se pudo reproducir el error, ahora que se encontró con el mismo error (creo que es el mismo, o relacionado al menos), tal vez es un buen momento para volver a abrir este informe. (No encontré ninguna otra referencia a esto, así que supongo que no se ha corregido)