28 votes

Est-ce la seule façon d'enseigner quelque chose à un cadre Java sur la fonction Aero Snap de Windows ?

Si je minimise une JFrame qui a été Aéro-ancrée à gauche de l'écran en cliquant sur l'minimiser le bouton de la Windows WindowDecoration et d'agrandir par Alt-Tab ou en cliquant dans la barre des tâches de Windows, le cadre devient restauré correctement ancrée à gauche. Bon!

Mais si je réduis l'image par

setExtendedState( getExtendedState() | Frame.ICONIFIED );

et regardez l'aperçu en passant la souris sur la barre des tâches de Windows, il montre l'image d'une mauvaise position. Après unminimizing par Alt-Tab ou en cliquant dans la barre des tâches de Windows, l'image est reconstituée à cette mauvaise position et de la taille. Le cadre, les limites sont les "unsnapped" valeurs", qui normalement, Windows se souvient de restaurer si vous faites glisser le cadre de l'ScreenBorder.

Un enregistrement d'écran du Bug:

enter image description here

Ma conclusion est que Java ne sait pas sur AeroSnap et offre le mauvais limites pour Windows. (Par exemple, Toolkit.getDefaultToolkit().isFrameStateSupported( Frame.MAXIMIZED_VERT ) ); renvoie la valeur false.)

C'est mon fix pour le 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 );
      }
    } );
  }
}

Cela semble fonctionner pour toutes les situations sous Windows7, mais il se sent comme trop déconner avec la fenêtre de gestion. Et j'ai évité de tester cette sous Linux ou MacOS pour une raison ;-)

Est-il un meilleur moyen de faire AeroSnap et Java Cadres de travailler ensemble?


Edit:

J'ai déposé un bug chez Oracle: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8147840

6voto

user1803551 Points 6057

Est-il un meilleur moyen de faire AeroSnap et Java Cadres de travailler ensemble?

Pas beaucoup mieux. La définition directe de l'état étendu contourne le système d'exploitation du traitement de réglage.

Si vous regardez le code source de l' JFrame#setExtendedState vous verrez qu'il appelle l' FramePeers' setState méthode. Le JDK de l' JFrame de la mise en œuvre de l' FramePeer interface est l' WFramePeer classe, qui déclare setState méthode de native. Donc, vous êtes hors de la chance jusqu'à ce que Oracle n'quelque chose ou que vous utilisez le code natif (voir ci-dessous).

Heureusement, vous n'avez pas nécessairement aller de noix avec des écouteurs d'événements et la mise en cache des limites. Masquage et affichage de la trame est assez pour "réinitialiser" la taille de ce qu'il était avant la minimisation:

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

Si cela a un effet secondaire de ne pas donner un aperçu détaillé de la structure de contenu:

enter image description here

La Solution à l'aide du code natif

Si vous voulez de l'utilisation JNA, vous pouvez complètement imiter le natif de la plate-forme de la minimisation. Vous aurez besoin d'inclure jna.jar et jna-platform.jar dans votre build path.

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

C'est assez explicite. Vous obtenez un pointeur vers la fenêtre et utiliser le natif CloseWindow (ce qui réduit effectivement, allez comprendre) sur elle. Notez que le minimaliste façon dont je l'ai écrit, il sera la cause d'un petit retard la première fois que le bouton est pressé parce que l' User32 instance est chargée. Vous pouvez charger au démarrage pour éviter ce premier temps de retard.

Le crédit va à la accepté de répondre ici.

0voto

Mayuso Points 451

Cela semble être un bug de la Balançoire. Le rapport de bug sur le Bug de la Base de données:

JDK-7029238 : componentResized pas appelé lorsque le formulaire est cassé

Dans ce rapport, le bug n'a pas pu être reproduit, maintenant vous avez rencontré le même bug (je pense que c'est la même chose, ou lié à au moins), peut-être que c'est un bon moment pour ré-ouvrir ce rapport. (Je n'ai trouvé aucune autre référence à cela, je suppose qu'il n'en a pas été résolu)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X