Wie bringt man ein Fenster nach vorne?


90

Wir haben eine Java-Anwendung, die in den Vordergrund gerückt werden muss, wenn ein Telekontrollmechanismus etwas in der Anwendung aktiviert.

Um dies zu erreichen, haben wir in der aufgerufenen Methode der Klasse, die den Rahmen unserer Anwendung darstellt (Erweiterung von a JFrame), folgende Implementierung realisiert:

setVisible(true);
toFront();

Unter Windows XP funktioniert dies beim ersten Aufruf. Beim zweiten Mal blinkt nur die Registerkarte in der Taskleiste. Der Rahmen wird nicht mehr nach vorne verschoben. Gleiches gilt für Win2k. Unter Vista scheint es gut zu funktionieren.

Hast du eine Idee?


Haben Sie ein Beispiel für dieses Verhalten?
OscarRyz

3
Die richtige Antwort ist, toFront()das EDT mit aufzurufen invokeLater. Im Folgenden finden Sie eine einfache Antwort, die jedoch nicht akzeptiert wird. Es funktioniert jedoch. Perfekt.
Erick Robertson

Ich weiß, das ist alt, aber das passiert auch unter OSX
Ferdil

Ich habe dieses Problem, aber keine der folgenden Antworten scheint es zu lösen. Ich bin sicher, dass es durch Fenster verursacht wird, die es mir nicht erlauben, den Fokus für mein erstes Fenster in der Anwendung zu stehlen.
Craig Warren

Antworten:


69

Eine mögliche Lösung ist:

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

8
Vielleicht sollte man zuerst den gesamten UI-Code in invokeLater starten? ;)
java.is.for.desktop.indeed

2
Hat bei mir in Java 7 unter KDE 4.9.5 nicht funktioniert, das Fenster würde sich immer noch unter anderen Programmen verstecken. Was mir geholfen hat, war die Änderung der Reihenfolge, in der die Fenster nach vorne gebracht wurden. Anstatt ein Fenster auszublenden und das zweite Fenster anzuzeigen, zeigen Sie das zweite Fenster an und verbergen dann das erste Fenster (JFrame).
Lekensteyn

1
Funktioniert mit Windows 10 unter Java 1.8 in einem Applet
Elliott

Was wäre die inverse Methode?
Kardinal - Wiedereinsetzung Monica

33

Ich hatte das gleiche Problem damit JFrame, unter Ubuntu (Java 1.6.0_10) ein nach vorne zu bringen. Und der einzige Weg, wie ich es lösen könnte, ist die Bereitstellung eines WindowListener. Insbesondere musste ich meine so einstellen JFrame, dass sie immer auf dem neuesten Stand toFront()ist, wenn sie aufgerufen wird, und windowDeactivatedEvent-Handler bereitstellen setAlwaysOnTop(false).


Hier ist also der Code, der in eine Basis JFrameeingefügt werden kann, mit der alle Anwendungsrahmen abgeleitet werden.

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

Wann immer Ihr Rahmen angezeigt oder zum Front Call gebracht werden soll frame.setVisible(true).

Seit ich zu Ubuntu 9.04 gewechselt bin, scheint es nicht nötig zu sein, ein WindowListenerzum Aufrufen zu haben super.setAlwaysOnTop(false)- wie zu beobachten ist; Dieser Code wurde in die Methoden toFront()und verschoben setVisible().

Bitte beachten Sie, dass die Methode setVisible()bei EDT immer aufgerufen werden sollte.


Vielen Dank! Ebenfalls verwandt ist diese Frage: stackoverflow.com/questions/2315560/…
rogerdpack

Es wird von mir aufgrund der setDisposed () -Methode nicht kompiliert. Kann nicht gefunden werden.
Ka3ak

1
@ ka3ak Dies ist ein geschützter Setter, der in die vorgeschlagene JFrame-Basisklasse eingeführt werden könnte, um die Situation mit dem zu entsorgenden Frame zu verfolgen. Die Methode dispose () müsste mit einem Aufruf von setDisposed (true) überschrieben werden. Dies ist nicht unbedingt für alle erforderlich.
01.

1
Das .setAlwaysOnTop(true);war das einzige, das bei der Verwendung eines JWindow für mich funktioniert hat.
DGolberg

setAlwaysOnTop(true)Nur so kann ich es unter Windows 10 zum Laufen bringen - danke!
Hartmut P.

22

Windows kann verhindern, dass Fenster den Fokus stehlen. Stattdessen blinkt das Taskleistensymbol. In XP ist es standardmäßig aktiviert (der einzige Ort, an dem ich Änderungen vorgenommen habe, ist die Verwendung von TweakUI, aber irgendwo gibt es eine Registrierungseinstellung). In Vista haben sie möglicherweise die Standardeinstellung geändert und / oder sie als vom Benutzer zugängliche Einstellung mit der sofort einsatzbereiten Benutzeroberfläche verfügbar gemacht.

Seit Windows 2K ist es eine Funktion, zu verhindern, dass sich Fenster nach vorne zwingen und den Fokus übernehmen (und ich bin dankbar dafür).

Trotzdem habe ich eine kleine Java-App, mit der ich mich daran erinnere, meine Aktivitäten während der Arbeit aufzuzeichnen, und die sich alle 30 Minuten zum aktiven Fenster macht (natürlich konfigurierbar). Es funktioniert unter Windows XP immer konsistent und blinkt nie im Fenster der Titelleiste. Es verwendet den folgenden Code, der im UI-Thread als Ergebnis eines Timer-Ereignisauslösens aufgerufen wird:

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

(Die erste Zeile wird wiederhergestellt, wenn sie minimiert wird ... tatsächlich würde sie wiederhergestellt, wenn sie ebenfalls maximiert wird, aber ich habe sie nie so).

Während ich diese App normalerweise minimiert habe, steht sie oft einfach hinter meinem Texteditor. Und wie gesagt, es funktioniert immer.

Ich habe eine Idee, was Ihr Problem sein könnte - vielleicht haben Sie eine Race-Bedingung mit dem Aufruf setVisible (). toFront () ist möglicherweise nur gültig, wenn das Fenster beim Aufruf tatsächlich angezeigt wird. Ich hatte dieses Problem schon einmal mit requestFocus (). Möglicherweise müssen Sie den Aufruf toFront () in einem UI-Listener für ein fensteraktiviertes Ereignis einfügen.

07.09.2014: Irgendwann funktionierte der obige Code nicht mehr, möglicherweise unter Java 6 oder 7. Nach einigen Untersuchungen und Experimenten musste ich den Code aktualisieren, um die toFrontMethode des Fensters zu überschreiben. Führen Sie dies aus (in Verbindung mit geändertem Code von was befindet sich über):

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

Ab Java 8_20 scheint dieser Code einwandfrei zu funktionieren.


1
+1 für die Unterstützung, dass Fenster den Fokus nicht stehlen dürfen. Ich hasse es, wenn das passiert, wenn ich ein Dokument eintippe.
Ken Paul

1
Ich stimme Ihnen voll und ganz zu, dass Sie den Fokus nicht stehlen, aber in diesem Fall erwartet der Benutzer, dass die Anwendung in den Vordergrund tritt. Es wäre jedoch nicht cool, die Registrierungseinstellungen und das gesamte Windows-Verhalten zu ändern.
Boutta

Ich vermute, das super.setAlwaysOnTop(false);ist so, dass das Fenster nicht immer oben ist, was notwendig ist, um das zu entfernen, was truewir zuvor eingestellt haben, um das Fenster nach vorne zu bringen, richtig? Ich frage, weil mit Ihrem Code das Fenster in meinem Fall immer immer oben ist, was ich offensichtlich nicht will. Laufen jre1.8.0_66 unter Windows 10.
Bram Vanroy

@Bram: Ja das stimmt. Ich führe den Code unter derselben Version von Java und Windows aus und er landet nicht immer über anderen Fenstern. Es ist möglicherweise nicht notwendig, immer oben zu setzen, aber ich denke, ansonsten blinkt Windows nur die Titelleiste, zumindest unter bestimmten Bedingungen.
Lawrence Dol

Hm, seltsam. Könnten Sie sich eine ähnliche Frage ansehen, in der ich auf diese Antwort verweise? Vielleicht zeigt dieser Code das Problem deutlicher: stackoverflow.com/questions/34637597/…
Bram Vanroy

11

Hier ist eine Methode, die WIRKLICH funktioniert (unter Windows Vista getestet): D.

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

Die Vollbildvariable gibt an, ob die App im Vollbildmodus oder im Fenster ausgeführt werden soll.

Dadurch blinkt die Taskleiste nicht, sondern das Fenster wird zuverlässig nach vorne gebracht.


Vielen Dank für den setExtendedState-Tipp. Ich habe es zusammen mit der Lösung toFront () und repaint () verwendet, um das Fenster in den Vordergrund zu bringen, auch wenn es minimiert wurde.
Rob

1
Bestätigt: Diese Lösung funktioniert unter Windows XP. Die Verwendung von toFront führt zu einer blinkenden Meldung in der Taskleiste. Vielen Dank!
Eric Lindauer

5

Hj, alle Ihre Methoden funktionieren in Fedora KDE 14 nicht für mich. Ich habe eine schmutzige Möglichkeit, ein Fenster nach vorne zu bringen, während wir darauf warten, dass Oracle dieses Problem behebt.

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

  //...

}

Und das funktioniert perfekt in meinem Fedora KDE 14 :-)


Ein bisschen hacky, funktioniert bei uns aber nur beim ersten Anruf :-). (Kubuntu 12.04) - andere Lösung ist fehlgeschlagen
user85155

Dies war die einzige Lösung, die für mich (Windows Server 2012 R2) bei einem Problem funktioniert hat, bei dem ein JFrame (Login) geöffnet wird, der jedoch erst dann den Fokus hat, wenn der Benutzer darauf klickt.
Glenneroo

4

Diese einfache Methode hat in Windows 7 perfekt funktioniert:

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

2
Das repaint()ist nicht nötig, das invokeLater()hat es geschafft. Danke dir.
Matthieu

4

Ich habe deine Antworten getestet und nur die von Stefan Reich hat für mich gearbeitet. Obwohl ich es nicht geschafft habe, das Fenster in seinen vorherigen Zustand zurückzusetzen (maximiert / normal). Ich fand diese Mutation besser:

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

Das ist setStatestatt setExtendedState.


3

Am einfachsten habe ich festgestellt, dass es keine plattformübergreifende Inkonsistenz gibt:

setVisible (false); setVisible (true);


1
Verursacht ein Blinken, nicht wahr? nett und einfach aber :)
Rogerdpack

hat für meinen Hintergrundprozess nicht funktioniert. Außerdem wird das Fenster für die erste Aktualisierung weiß angezeigt, wenn es vom Vordergrundprozess aufgerufen wird. Kann nicht für Bildschirmaufnahmen verwendet werden.
DragonLord

Das Blinken kann vermieden werden, indem überprüft wird, ob das Fenster symbolisiert ist oder nicht
bis

2

Die Regeln, die festlegen, was passiert, wenn Sie .toFront () einen JFrame verwenden, sind in Windows und Linux identisch:

-> Wenn ein Fenster der vorhandenen Anwendung derzeit das fokussierte Fenster ist, wechselt der Fokus zum angeforderten Fenster. -> Wenn nicht, blinkt das Fenster lediglich in der Taskleiste

ABER :

-> Neue Fenster werden automatisch fokussiert

Also lasst uns das ausnutzen! Sie möchten ein Fenster nach vorne bringen, wie geht das? Gut :

  1. Erstellen Sie ein leeres Nichtzweckfenster
  2. Zeig es
  3. Warten Sie, bis es auf dem Bildschirm angezeigt wird (setVisible macht das)
  4. Wenn angezeigt, fordern Sie den Fokus für das Fenster an, auf das Sie den Fokus tatsächlich setzen möchten
  5. verstecke das leere Fenster, zerstöre es

Oder im Java-Code:

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

Hat unter Win7 nicht funktioniert, beide Fenster blinken (wenn ich das zweite nicht verstecke).
NateS

Kreativ. Hat für meinen Hintergrundprozess unter Win7 nicht funktioniert, wenn es behandelt wurde. Neuer Rahmen kommt nicht oben an. Älteres JDK 6u21.
DragonLord

0

Im Javadoc gibt es zahlreiche Einschränkungen für die Methode toFront (), die möglicherweise Ihr Problem verursachen.

Aber ich werde trotzdem raten, wenn "nur die Registerkarte in der Taskleiste blinkt", wurde die Anwendung minimiert? In diesem Fall kann die folgende Zeile aus dem Javadoc zutreffen:

"Wenn dieses Fenster sichtbar ist, wird dieses Fenster nach vorne gebracht und möglicherweise zum fokussierten Fenster."


0

Um zu vermeiden, dass das Fenster den Fokus verliert, wenn es nach dem Ausblenden wieder sichtbar wird, ist Folgendes erforderlich:

setExtendedState(JFrame.NORMAL);

Wie so:

defaultItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                showWindow();
                setExtendedState(JFrame.NORMAL);
            }
});
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.