web-dev-qa-db-fra.com

Comment amener une fenêtre à l'avant?

Nous avons une application Java qui doit être mise au premier plan lorsqu'un mécanisme de télécontrôle active quelque chose dans l'application.

Pour obtenir cela, nous avons réalisé dans la méthode appelée de la classe qui représente le cadre de notre application (extension d'un JFrame) après la mise en oeuvre:

setVisible(true);
toFront();

Sous Windows XP, cela fonctionne la première fois qu'il est appelé, et la deuxième fois, seul l'onglet de la barre des tâches clignote, le cadre n'apparaît plus au premier plan. Même chose pour Win2k. Sur Vista, cela semble bien fonctionner.

Avez-vous des idées?

84
boutta

Une solution possible est:

Java.awt.EventQueue.invokeLater(new Runnable() {
    @Override
    public void run() {
        myFrame.toFront();
        myFrame.repaint();
    }
});
64

J'ai eu le même problème en apportant une JFrame au premier plan sous Ubuntu (Java 1.6.0_10). Et le seul moyen de résoudre ce problème est de fournir un WindowListener. Plus précisément, je devais configurer ma JFrame pour qu'elle reste toujours au top lorsque toFront() est invoquée et fournir le gestionnaire d'événements windowDeactivated à setAlwaysOnTop(false)


Donc, voici le code qui pourrait être placé dans une base JFrame, qui est utilisée pour dériver tous les cadres d’application.

@Override
public void setVisible(final boolean visible) {
  // make sure that frame is marked as not disposed if it is asked to be visible
  if (visible) {
      setDisposed(false);
  }
  // let's handle visibility...
  if (!visible || !isVisible()) { // have to check this condition simply because super.setVisible(true) invokes toFront if frame was already visible
      super.setVisible(visible);
  }
  // ...and bring frame to the front.. in a strange and weird way
  if (visible) {
      toFront();
  }
}

@Override
public void toFront() {
  super.setVisible(true);
  int state = super.getExtendedState();
  state &= ~JFrame.ICONIFIED;
  super.setExtendedState(state);
  super.setAlwaysOnTop(true);
  super.toFront();
  super.requestFocus();
  super.setAlwaysOnTop(false);
}

Chaque fois que votre cadre doit être affiché ou mis au premier plan, appelez frame.setVisible(true).

Depuis que j'ai migré vers Ubuntu 9.04, il semble inutile de disposer d'une WindowListener pour invoquer super.setAlwaysOnTop(false) - comme on peut l'observer; ce code a été déplacé vers les méthodes toFront() et setVisible().

Veuillez noter que la méthode setVisible() doit toujours être invoquée sur EDT.

33
01es

Windows a la possibilité d'empêcher Windows de voler le focus; à la place, l'icône de la barre des tâches clignote. Dans XP, il est activé par défaut (le seul endroit où j'ai constaté une modification utilise TweakUI, mais il existe un paramètre de registre quelque part). Sous Vista, ils peuvent avoir modifié la valeur par défaut et/ou l'exposer en tant que paramètre accessible à l'utilisateur avec l'interface utilisateur prête à l'emploi.

Empêcher les fenêtres de s’imposer et de se concentrer est une fonctionnalité depuis Windows 2K (et moi, je l’en suis reconnaissant).

Cela dit, j’utilise une petite application Java pour me rappeler d’enregistrer mes activités tout en travaillant et c’est elle-même la fenêtre active toutes les 30 minutes (configurable bien sûr). Il fonctionne toujours de manière cohérente sous Windows XP et ne fait jamais clignoter la fenêtre de la barre de titre. Il utilise le code suivant, appelé dans le thread d'interface utilisateur à la suite du déclenchement d'un événement timer:

if(getState()!=Frame.NORMAL) { setState(Frame.NORMAL); }
toFront();
repaint();

(la première ligne restaure si minimisée ... en fait, elle le restaurera aussi si elle est maximisée, mais je ne l'ai jamais ainsi).

Bien que cette application soit généralement réduite au minimum, elle se trouve souvent derrière mon éditeur de texte. Et, comme je l'ai dit, cela fonctionne toujours.

J'ai une idée de ce que votre problème pourrait être - peut-être vous avez une condition de concurrence avec l'appel setVisible (). toFront () peut ne pas être valide à moins que la fenêtre ne soit réellement affichée à l'appel. J'ai déjà eu ce problème avec requestFocus (). Vous devrez peut-être placer l'appel toFront () dans un écouteur d'interface utilisateur sur un événement activé par une fenêtre.

2014-09-07: À un moment donné, le code ci-dessus a cessé de fonctionner, peut-être sous Java 6 ou 7. Après quelques recherches et expérimentations, j'ai dû mettre à jour le code pour surcharger la méthode toFront de la fenêtre avec le code modifié de ce qui est ci-dessus):

setVisible(true);
toFront();
requestFocus();
repaint();

...

public @Override void toFront() {
    int sta = super.getExtendedState() & ~JFrame.ICONIFIED & JFrame.NORMAL;

    super.setExtendedState(sta);
    super.setAlwaysOnTop(true);
    super.toFront();
    super.requestFocus();
    super.setAlwaysOnTop(false);
}

Depuis Java 8_20, ce code semble bien fonctionner.

21
Lawrence Dol

Voici une méthode qui fonctionne vraiment (testé sur Windows Vista): D

   frame.setExtendedState(JFrame.ICONIFIED);
   frame.setExtendedState(fullscreen ? JFrame.MAXIMIZED_BOTH : JFrame.NORMAL);

La variable plein écran indique si vous souhaitez que l'application s'exécute en plein écran ou en fenêtre.

Cela ne fait pas clignoter la barre des tâches, mais amène la fenêtre de manière fiable.

11
Stefan Reich

Hj, toutes vos méthodes ne fonctionnent pas pour moi, dans Fedora KDE 14. J'ai un mauvais moyen de mettre une fenêtre à l’avant, en attendant que Oracle corrige ce problème.

import Java.awt.MouseInfo;
import Java.awt.Point;
import Java.awt.Robot;
import Java.awt.event.InputEvent;

public class FrameMain extends javax.swing.JFrame {

  //...
  private final javax.swing.JFrame mainFrame = this;

  private void toggleVisible() {
    setVisible(!isVisible());
    if (isVisible()) {
      toFront();
      requestFocus();
      setAlwaysOnTop(true);
      try {
        //remember the last location of mouse
        final Point oldMouseLocation = MouseInfo.getPointerInfo().getLocation();

        //simulate a mouse click on title bar of window
        Robot robot = new Robot();
        robot.mouseMove(mainFrame.getX() + 100, mainFrame.getY() + 5);
        robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
        robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);

        //move mouse to old location
        robot.mouseMove((int) oldMouseLocation.getX(), (int) oldMouseLocation.getY());
      } catch (Exception ex) {
        //just ignore exception, or you can handle it as you want
      } finally {
        setAlwaysOnTop(false);
      }
    }
  }

  //...

}

Et cela fonctionne parfaitement dans mon Fedora KDE 14 :-)

5
user942821

Cette méthode simple a parfaitement fonctionné pour moi sous Windows 7:

    private void BringToFront() {
        Java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                if(jFrame != null) {
                    jFrame.toFront();
                    jFrame.repaint();
                }
            }
        });
    }
4
Mr Ed

J'ai testé vos réponses et seulement celle de Stefan Reich a fonctionné pour moi. Bien que je n'ai pas réussi à restaurer la fenêtre à son état précédent (maximisé/normal). J'ai trouvé cette mutation mieux:

view.setState(Java.awt.Frame.ICONIFIED);
view.setState(Java.awt.Frame.NORMAL);

C'est setState au lieu de setExtendedState.

3
Jarekczek

Le moyen le plus simple que j'ai trouvé ne présente pas d'incohérence sur toutes les plateformes:

setVisible (false); setVisible (true);

3
Rich

Les règles régissant ce qui se passe lorsque vous utilisez .toFront () un JFrame sont les mêmes dans Windows et Linux:

-> si une fenêtre de l'application existante est actuellement la fenêtre active, celle-ci bascule vers la fenêtre demandée -> sinon, la fenêtre clignote simplement dans la barre des tâches

MAIS : 

-> les nouvelles fenêtres obtiennent automatiquement le focus

Alors exploitons cela! Vous voulez apporter une fenêtre à l'avant, comment le faire? Bien :

  1. Créer une fenêtre non-usage vide
  2. Montre le
  3. Attendez qu'il apparaisse à l'écran (setVisible le fait)
  4. Lorsque cette option est affichée, demandez le focus à la fenêtre sur laquelle vous souhaitez réellement le mettre en évidence.
  5. cache la fenêtre vide, détruis-la

Ou, en code Java:

// unminimize if necessary
this.setExtendedState(this.getExtendedState() & ~JFrame.ICONIFIED);

// don't blame me, blame my upbringing
// or better yet, blame Java !
final JFrame newFrame = new JFrame();
newFrame.add(new JLabel("boembabies, is this in front ?"));

newFrame.pack();
newFrame.setVisible(true);
newFrame.toFront();

this.toFront();
this.requestFocus();

// I'm not 100% positive invokeLater is necessary, but it seems to be on
// WinXP. I'd be lying if I said I understand why
SwingUtilities.invokeLater(new Runnable() {
  @Override public void run() {
    newFrame.setVisible(false);
  }
});
2
christopher

Il existe de nombreux mises en garde dans le fichier javadoc pour la méthode toFront () qui peuvent être à l'origine du problème. 

Mais je vais quand même deviner, quand "seul l'onglet de la barre des tâches clignote", l'application a-t-elle été réduite? Si c'est le cas, la ligne suivante du javadoc peut s'appliquer:

"Si cette fenêtre est visible, amène cette fenêtre au premier plan et peut en faire la fenêtre ciblée." 

0
Brendan Cashman

Pour éviter que la fenêtre ne perde le focus lorsqu'elle redevient visible après avoir été masquée, il suffit de:

setExtendedState(JFrame.NORMAL);

Ainsi:

defaultItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                showWindow();
                setExtendedState(JFrame.NORMAL);
            }
});
0