it-swarm.com.de

Wie bringt man ein Fenster nach vorne?

Wir haben eine Java-Anwendung, die in den Vordergrund gestellt werden muss, wenn ein Fernwirkmechanismus etwas in der Anwendung aktiviert.

Um dies zu erreichen, haben wir in der aufgerufenen Methode der Klasse, die den Rahmen unserer Anwendung (Erweiterung einer JFrame) darstellt, 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 kommt nicht mehr in den Vordergrund. Gleiches gilt für Win2k. Unter Vista scheint es gut zu funktionieren.

Hast du eine Idee?

84
boutta

Eine mögliche Lösung ist:

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

Das gleiche Problem hatte ich, als ich unter Ubuntu (Java 1.6.0_10) eine JFrame nach vorne brachte. Und die einzige Möglichkeit, das Problem zu lösen, ist die Angabe einer WindowListener. Insbesondere musste ich meine JFrame so einstellen, dass sie bei jedem Aufruf von toFront() immer im Vordergrund bleibt und dem setAlwaysOnTop(false)windowDeactivated-Ereignishandler zur Verfügung stellt. 


Hier ist der Code, der in eine Basis JFrame eingefügt werden könnte, mit der alle Anwendungsframes 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 Frame angezeigt oder in den Vordergrund gerufen werden soll, rufen Sie frame.setVisible(true) auf.

Seit ich auf Ubuntu 9.04 umgezogen bin, scheint es nicht nötig zu sein, eine WindowListener für den Aufruf von super.setAlwaysOnTop(false) zu haben, wie man beobachten kann. Dieser Code wurde in die Methoden toFront() und setVisible() verschoben.

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

33
01es

Windows hat die Möglichkeit, zu verhindern, dass Fenster den Fokus stehlen. Stattdessen blinkt das Taskleistensymbol. In XP ist es standardmäßig aktiviert (der einzige Ort, den ich ändern konnte, ist TweakUI, aber irgendwo ist eine Registrierungseinstellung vorhanden). In Vista haben sie möglicherweise die Standardeinstellung geändert und/oder sie als vom Benutzer zugängliche Einstellung mit der Standardbenutzeroberfläche angezeigt.

Das Verhindern, dass sich Fenster nach vorne drängen und den Fokus übernehmen, ist eine Funktion seit Windows 2K (und ich bin dankbar dafür).

Das heißt, ich habe eine kleine Java-App, mit der ich daran erinnert werde, meine Aktivitäten während der Arbeit aufzuzeichnen, und sie wird alle 30 Minuten zum aktiven Fenster (natürlich konfigurierbar). Es funktioniert immer unter Windows XP und blinkt niemals im Titelleistenfenster. Es verwendet den folgenden Code, der im UI-Thread als Ergebnis eines Timer-Ereignisses aufgerufen wird:

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

(Die erste Zeile wird wiederhergestellt, wenn sie minimiert ist ... sie würde sie auch wiederherstellen, wenn sie maximiert wird, aber ich habe sie nie so).

Während ich diese App normalerweise minimiert habe, liegt sie oft hinter meinem Texteditor. Und wie ich schon sagte, es funktioniert immer.

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

2014-09-07: Irgendwann hat der obige Code nicht mehr funktioniert, vielleicht bei Java 6 oder 7. Nach einigen Untersuchungen und Experimenten musste ich den Code aktualisieren, um die toFront-Methode des Fensters zu überschreiben mit modifiziertem Code von oben):

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 gut zu funktionieren.

21
Lawrence Dol

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

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

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

Die Taskleiste blinkt dadurch nicht, sondern bringt das Fenster zuverlässig nach vorne.

11
Stefan Reich

Hj, in Fedora KDE 14 funktionieren alle Ihre Methoden nicht für mich. Ich habe ein schmutziges Mittel, um ein Fenster nach vorne zu bringen, während wir auf Oracle warten, um dieses Problem zu beheben.

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 meiner Fedora KDE 14 :-)

5
user942821

Diese einfache Methode hat für mich 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();
                }
            }
        });
    }
4
Mr Ed

Ich habe Ihre Antworten getestet und nur die von Stefan Reich habe für mich gearbeitet. Ich habe es zwar nicht geschafft, das Fenster in seinem vorherigen Zustand (maximiert/normal) wiederherzustellen. Ich fand diese Mutation besser:

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

Das ist setState anstelle von setExtendedState.

3
Jarekczek

Die einfachste Methode, die ich gefunden habe, ist nicht plattformübergreifend:

setVisible (false); setVisible (true);

3
Rich

Die Regeln für das, was passiert, wenn Sie .toFront () einen JFrame verwenden, sind in Windows und Linux die gleichen:

-> Wenn ein Fenster der vorhandenen Anwendung derzeit das fokussierte Fenster ist, wechselt der Fokus auf das angeforderte Fenster

ABER : 

-> Neue Fenster erhalten automatisch den Fokus

Also lasst uns das ausnutzen! Sie wollen 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 erscheint (setVisible macht das)
  4. Wenn Sie angezeigt werden, fordern Sie den Fokus für das Fenster an, in das Sie den Fokus bringen möchten
  5. verstecken Sie das leere Fenster, zerstören Sie 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);
  }
});
2
christopher

Es gibt zahlreiche Vorbehalte im Javadoc für die toFront () - Methode, die Ihr Problem verursachen kann. 

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

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

0
Brendan Cashman

Um zu vermeiden, dass das Fenster den Fokus verliert, wenn es wieder sichtbar wird, nachdem es ausgeblendet wurde, ist Folgendes erforderlich:

setExtendedState(JFrame.NORMAL);

So wie:

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