Comment amener une fenêtre à l'avant?


90

Nous avons une application Java qui doit être mise au premier plan lorsqu'un mécanisme de télécommande 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 de a JFrame) suite de l'implémentation:

setVisible(true);
toFront();

Sous Windows XP, cela fonctionne la première fois qu'il est appelé, la deuxième fois que seul l'onglet dans la barre des tâches clignote, le cadre ne vient plus au premier plan. Il en va de même pour Win2k. Sur Vista, cela semble fonctionner correctement.

As tu des idées?


avez-vous un exemple de ce comportement?
OscarRyz

3
La bonne réponse est d'appeler toFront()l'EDT en utilisant invokeLater. Il y a une réponse simple incluse ci-dessous, mais ce n'est pas la réponse acceptée. Cela fonctionne, cependant. À la perfection.
Erick Robertson

Je sais que c'est vieux, mais cela se produit aussi sur OSX
ferdil

Je rencontre ce problème, mais aucune des réponses ci-dessous ne semble le résoudre. Je suis sûr que cela est dû au fait que les fenêtres ne me permettent pas de «voler» le focus pour ma première fenêtre dans l'application.
Craig Warren

Réponses:


69

Une solution possible est:

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

8
Peut-être devrait-on commencer tout le code d'interface utilisateur à l'intérieur d'invokeLater? ;)
java.is.for.desktop.indeed

2
Ne fonctionnait pas pour moi dans Java 7 sur KDE 4.9.5, la fenêtre se cacherait toujours sous d'autres programmes. Ce qui m'a aidé, c'est de changer l'ordre d'amener les fenêtres à l'avant. Au lieu de masquer une fenêtre et d'afficher la deuxième fenêtre, affichez la deuxième fenêtre, puis masquez la première fenêtre (JFrame).
Lekensteyn

1
Fonctionne avec Windows 10 exécutant Java 1.8 dans une applet
Elliott

Quelle serait la méthode inverse?
Cardinal - Réintégrer Monica le

33

J'ai eu le même problème en mettant un JFrameà l'avant sous Ubuntu (Java 1.6.0_10). Et la seule façon de résoudre ce problème est de fournir un fichier WindowListener. Plus précisément, j'ai dû configurer my JFramepour qu'il reste toujours au top chaque fois qu'il toFront()est invoqué et fournir windowDeactivatedun gestionnaire d'événements à 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 frame.setVisible(true).

Depuis que je suis passé à Ubuntu 9.04, il ne semble pas nécessaire d'avoir un WindowListenerpour 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.


Merci! Cette question est également liée: stackoverflow.com/questions/2315560/…
rogerdpack

Il ne compile pas par moi à cause de la méthode setDisposed (). Impossible de trouver.
ka3ak

1
@ ka3ak C'est un setter protégé qui pourrait être introduit dans la classe de base JFrame suggérée afin de suivre la situation avec la trame supprimée. La méthode dispose () devrait être remplacée par un appel à setDisposed (true). Ce n'est pas à proprement parler nécessaire pour tout le monde.
01es

1
Le .setAlwaysOnTop(true);était le seul qui a fonctionné pour moi lors de l' utilisation d' un JWindow.
DGolberg

setAlwaysOnTop(true)est le seul moyen de le faire fonctionner sous Windows 10 - merci!
Hartmut P.

22

Windows a la possibilité d'empêcher les fenêtres de voler le focus; à la place, il fait clignoter l'icône de la barre des tâches. Dans XP, il est activé par défaut (le seul endroit où j'ai vu le changer est d'utiliser TweakUI, mais il y a un paramètre de registre quelque part). Dans Vista, ils peuvent avoir modifié la valeur par défaut et / ou l'ont exposée en tant que paramètre accessible à l'utilisateur avec l'interface utilisateur prête à l'emploi.

Empêcher les fenêtres de se forcer à l'avant et de se concentrer est une fonctionnalité depuis Windows 2K (et je suis, pour ma part, reconnaissant pour cela).

Cela dit, j'ai une petite application Java que j'utilise pour me rappeler d'enregistrer mes activités pendant que je travaille, et elle se fait 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 de minuterie:

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

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

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

J'ai une idée de ce que pourrait être votre problème - peut-être avez-vous 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 lorsqu'elle est appelée; 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 la fenêtre.

2014-09-07: À un moment donné, le code ci-dessus a cessé de fonctionner, peut-être à Java 6 ou 7. Après quelques recherches et expérimentations, j'ai dû mettre à jour le code pour remplacer la toFrontméthode de la fenêtre (en conjonction avec le code modifié de ce est au-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);
}

À partir de Java 8_20, ce code semble fonctionner correctement.


1
+1 pour ne pas permettre aux fenêtres de voler la mise au point. Je déteste quand cela se produit lorsque je tape un document.
Ken Paul

1
Je suis tout à fait d'accord avec vous contre le vol de focus, mais dans ce cas précis, l'utilisateur s'attend à ce que l'application vienne au premier plan. Mais il ne serait pas cool de changer les paramètres de registre et de changer le comportement complet de Windows.
boutta

Je suppose que super.setAlwaysOnTop(false);c'est pour que la fenêtre ne soit pas toujours au-dessus, ce qui est nécessaire pour se débarrasser de ce que truenous avons défini plus tôt pour amener la fenêtre à l'avant, n'est-ce pas ? Je demande parce qu'avec votre code, la fenêtre est toujours au top dans mon cas, ce que je ne veux évidemment pas. Exécution de jre1.8.0_66 sous Windows 10.
Bram Vanroy

@Bram: Oui, c'est exact. J'exécute le code sur la même version de Java et de Windows et il ne se retrouve pas toujours au-dessus des autres fenêtres. Il n'est peut-être pas nécessaire de toujours mettre en haut, mais je pense que sinon, Windows ne fait que clignoter la barre de titre, du moins dans certaines conditions.
Lawrence Dol

Hm, étrange. Pourriez-vous jeter un œil à une question similaire dans laquelle je renvoie à cette réponse? Peut-être que ce code montre plus clairement le problème: stackoverflow.com/questions/34637597/…
Bram Vanroy

11

Voici une méthode qui fonctionne VRAIMENT (testée 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 au premier plan de manière fiable.


Merci pour le conseil setExtendedState. Je l'ai utilisé avec les solutions toFront () et repaint () pour amener la fenêtre au premier plan même si elle était minimisée.
rob

1
Confirmé: cette solution fonctionne dans WindowsXP, l'utilisation de toFront entraîne un message clignotant dans la barre des tâches. Merci!
Eric Lindauer

5

Hj, toutes les méthodes que vous possédez ne fonctionnent pas pour moi, dans Fedora KDE 14. J'ai une mauvaise façon de faire apparaître une fenêtre, pendant que nous attendons qu'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 :-)


Un peu hacky, ça marche pour nous, mais seulement pour le premier appel :-). (Kubuntu 12.04) - Une autre solution a échoué
user85155

C'était la seule solution qui fonctionnait pour moi (Windows Server 2012 R2) pour un problème où un JFrame (connexion) est ouvert mais n'a pas le focus tant que l'utilisateur n'a pas cliqué dessus.
glenneroo

4

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

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

2
Le repaint()n'est pas nécessaire, le invokeLater()fait. Je vous remercie.
Matthieu

4

J'ai testé vos réponses et seule 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

Le moyen le plus simple que j'ai trouvé qui n'a pas d'incohérence entre les plates-formes:

setVisible (faux); setVisible (vrai);


1
provoque un certain clignotement, n'est-ce pas? gentil et simple cependant :)
rogerdpack

n'a pas fonctionné pour mon processus d'arrière-plan. La fenêtre devient également blanche pour la première actualisation si elle est appelée à partir du processus de premier plan. Ne peut pas utiliser pour les captures d'écran.
DragonLord

le clignotement peut être évité en vérifiant si la fenêtre est iconifiée ou non
totaam

2

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

-> si une fenêtre de l'application existante est actuellement la fenêtre focalisée, alors le focus passe à 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 ça! Vous souhaitez amener une fenêtre à l'avant, comment faire? Bien :

  1. Créer une fenêtre vide sans but
  2. Montre le
  3. Attendez qu'il apparaisse à l'écran (setVisible fait cela)
  4. Lorsqu'il est affiché, demandez le focus pour la fenêtre sur laquelle vous voulez réellement mettre le focus
  5. cachez la fenêtre vide, détruisez-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);
  }
});

N'a pas fonctionné sur Win7, les deux fenêtres clignotent (si je ne cache pas la 2ème).
NateS

Créatif. N'a pas fonctionné pour mon processus d'arrière-plan sur Win7, lorsqu'il est couvert. Le nouveau cadre ne vient pas en tête. Plus ancien JDK 6u21.
DragonLord

0

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

Mais je vais quand même deviner, quand "seul l'onglet dans la barre des tâches clignote", l'application a-t-elle été minimisée? Si tel 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 focalisée."


0

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);
            }
});
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.