Jak przesunąć okno do przodu?

90

Mamy aplikację Java, która musi zostać wyniesiona na pierwszy plan, gdy mechanizm telekontroli aktywuje coś w aplikacji.

W tym celu zrealizowaliśmy w wywołanej metodzie klasy reprezentującej szkielet naszej aplikacji (rozszerzenie a JFrame) następującą implementację:

setVisible(true);
toFront();

W systemie Windows XP działa to przy pierwszym wywołaniu, za drugim razem miga tylko karta na pasku zadań, ramka nie wysuwa się już z przodu. To samo dotyczy Win2k. Wydaje się, że na Vista działa dobrze.

Czy masz jakies pomysły?

boutta
źródło
czy masz próbkę tego zachowania?
OscarRyz
3
Prawidłową odpowiedzią jest wezwanie toFront()EDT za pomocą invokeLater. Poniżej znajduje się prosta odpowiedź, ale nie jest to akceptowana odpowiedź. Ale to działa. Doskonale.
Erick Robertson
Wiem, że to jest stare, ale dzieje się to również na OSX
ferdil
Doświadczam tego problemu, ale żadna z poniższych odpowiedzi nie wydaje się go rozwiązać. Jestem pewien, że jest to spowodowane tym, że okna nie pozwalają mi „ukraść” fokusu dla mojego pierwszego okna w aplikacji.
Craig Warren

Odpowiedzi:

69

Możliwe rozwiązanie to:

java.awt.EventQueue.invokeLater(new Runnable() {
    @Override
    public void run() {
        myFrame.toFront();
        myFrame.repaint();
    }
});
sth
źródło
8
Być może w pierwszej kolejności należy rozpocząć CAŁY kod interfejsu użytkownika wewnątrz invokeLater? ;)
java.is.for.desktop.indeed
2
Nie działało dla mnie w Javie 7 w KDE 4.9.5, okno nadal było ukrywane pod innymi programami. Pomogła mi zmiana kolejności wyprowadzania okien na przód. Zamiast ukrywać jedno okno i pokazywać drugie, pokaż drugie okno, a następnie ukryj pierwsze okno (JFrame).
Lekensteyn
1
Działa z systemem Windows 10 z Javą 1.8 w aplecie
Elliott
Jaka byłaby metoda odwrotna?
Kardynał - Przywróć Monikę
33

Miałem ten sam problem z przeniesieniem JFramena pierwszy plan pod Ubuntu (Java 1.6.0_10). Jedynym sposobem, w jaki mogłem to rozwiązać, jest dostarczenie pliku WindowListener. W szczególności musiałem ustawić moje, JFrameaby zawsze pozostawało na wierzchu, gdy toFront()jest wywoływane, i zapewniało windowDeactivatedobsługę zdarzeń setAlwaysOnTop(false).


Oto kod, który można umieścić w bazie JFrame, z której wyprowadzane są wszystkie ramki aplikacji.

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

Zawsze, gdy ramka powinna zostać wyświetlona lub przeniesiona na pierwszy plan frame.setVisible(true).

Odkąd przeniosłem się na Ubuntu 9.04 wydaje się, że nie ma potrzeby WindowListenerwywoływania super.setAlwaysOnTop(false)- jak można zaobserwować; ten kod został przeniesiony do metod toFront()i setVisible().

Należy pamiętać, że metoda setVisible()powinna być zawsze wywoływana w EDT.

01es
źródło
Dzięki! Powiązane jest również to pytanie: stackoverflow.com/questions/2315560/ ...
rogerdpack
Nie kompiluje się przeze mnie z powodu metody setDisposed (). Nie można znaleźć.
ka3ak
1
@ ka3ak To jest chroniona metoda ustawiająca, którą można wprowadzić w sugerowanej klasie bazowej JFrame w celu śledzenia sytuacji po usunięciu ramki. Metoda dispose () musiałaby zostać zastąpiona wywołaniem setDisposed (true). Nie jest to ściśle potrzebne dla wszystkich.
01es
1
.setAlwaysOnTop(true);Był jedynym, który pracował dla mnie podczas używania JWindow.
DGolberg
setAlwaysOnTop(true)to jedyny sposób na uruchomienie go pod Windows 10 - dzięki!
Hartmut P.
23

Windows ma funkcję zapobiegającą kradzieży ostrości; zamiast tego miga ikona na pasku zadań. W XP jest on domyślnie włączony (jedyne miejsce, w którym widziałem, aby go zmienić, używa TweakUI, ale gdzieś jest ustawienie rejestru). W systemie Vista mogli zmienić domyślne ustawienia i / lub ujawnić je jako ustawienie dostępne dla użytkownika za pomocą gotowego do użycia interfejsu użytkownika.

Zapobieganie przesuwaniu się okien do przodu i skupianiu się na nich jest funkcją od czasu Windows 2K (i jestem za to wdzięczny).

To powiedziawszy, mam małą aplikację Java, której używam, aby przypomnieć mi o rejestrowaniu moich działań podczas pracy i co 30 minut włącza się jako aktywne okno (oczywiście można je konfigurować). Zawsze działa konsekwentnie w systemie Windows XP i nigdy nie miga okno paska tytułu. Używa następującego kodu, wywoływanego w wątku interfejsu użytkownika w wyniku uruchomienia zdarzenia licznika czasu:

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

(pierwsza linia przywraca, jeśli jest zminimalizowana ... w rzeczywistości przywracałaby ją, gdyby była zmaksymalizowana, ale nigdy jej tak nie było).

Chociaż zwykle mam zminimalizowaną aplikację, często jest ona po prostu za moim edytorem tekstu. I, jak powiedziałem, zawsze działa.

Mam pojęcie, jaki może być twój problem - być może masz stan wyścigu z wywołaniem setVisible (). toFront () może nie być poprawne, chyba że okno jest faktycznie wyświetlane po wywołaniu; Już wcześniej miałem ten problem z requestFocus (). Może być konieczne umieszczenie wywołania toFront () w nasłuchiwaniu interfejsu użytkownika w zdarzeniu aktywowanym przez okno.

07.09.2014: W pewnym momencie powyższy kod przestał działać, być może w Javie 6 lub 7. Po pewnych badaniach i eksperymentach musiałem zaktualizować kod, aby nadpisać toFrontmetodę okna, zrób to (w połączeniu ze zmodyfikowanym kodem z tego, co jest ponad):

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

Od wersji Java 8_20 ten kod wydaje się działać poprawnie.

Lawrence Dol
źródło
1
+1 za wspieranie, które nie pozwala oknom ukraść ostrości. Nienawidzę, gdy tak się dzieje, gdy piszę dokument.
Ken Paul
1
Całkowicie zgadzam się z Tobą przeciwko kradzieży ostrości, ale w tym konkretnym przypadku użytkownik oczekuje, że aplikacja znajdzie się na pierwszym planie. Ale zmiana ustawień rejestru i zmiana całego zachowania systemu Windows nie byłaby fajna.
boutta
Domyślam się, że super.setAlwaysOnTop(false);jest tak, że okno nie zawsze jest na górze, co jest konieczne, aby pozbyć się tego, truektóry ustawiliśmy wcześniej, aby przesunąć okno do przodu, prawda? Pytam, ponieważ z twoim kodem okno jest zawsze na wierzchu w moim przypadku, czego oczywiście nie chcę. Uruchomiono jre1.8.0_66 w systemie Windows 10.
Bram Vanroy,
@Bram: Tak, zgadza się. Uruchamiam kod na tej samej wersji Javy i Windowsa i nie zawsze kończy się on na innych oknach. Może nie być konieczne ustawianie zawsze na wierzchu, ale myślę, że w przeciwnym razie Windows po prostu miga pasek tytułu, przynajmniej w pewnych warunkach.
Lawrence Dol,
Hm, dziwne. Czy mógłbyś spojrzeć na podobne pytanie, w którym odsyłam do tej odpowiedzi? Może ten kod lepiej pokazuje problem: stackoverflow.com/questions/34637597/ ...
Bram Vanroy
11

Oto metoda, która NAPRAWDĘ działa (przetestowana na Windows Vista): D

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

Zmienna pełnego ekranu wskazuje, czy aplikacja ma działać na pełnym ekranie, czy w oknie.

Nie powoduje to migania paska zadań, ale niezawodnie przenosi okno na wierzch.

Stefana Reicha
źródło
Dzięki za wskazówkę setExtendedState. Użyłem go razem z rozwiązaniem toFront () i repaint (), aby przenieść okno na pierwszy plan, nawet jeśli zostało zminimalizowane.
obrabować
1
Potwierdzone: to rozwiązanie działa w WindowsXP, użycie toFront powoduje miganie komunikatu na pasku zadań. Dzięki!
Eric Lindauer
5

Hj, wszystkie twoje metody nie działają dla mnie, w Fedorze KDE 14. Mam nieprzyjemny sposób na przeniesienie okna na wierzch, podczas gdy czekamy, aż Oracle naprawi ten problem.

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

  //...

}

I to działa doskonale w mojej Fedorze KDE 14 :-)


źródło
Trochę hacky, działa u nas, ale tylko na pierwszy telefon :-). (Kubuntu 12.04) - inne rozwiązanie
zawiodło
To było jedyne rozwiązanie, które działało dla mnie (Windows Server 2012 R2) w przypadku problemu, w którym JFrame (login) jest otwarta, ale nie jest aktywna, dopóki użytkownik jej nie kliknie.
glenneroo
4

Ta prosta metoda zadziałała idealnie w Windows 7:

    private void BringToFront() {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                if(jFrame != null) {
                    jFrame.toFront();
                    jFrame.repaint();
                }
            }
        });
    }
Panie Ed
źródło
2
Nie repaint()jest to konieczne, invokeLater()zrobiłem to. Dziękuję Ci.
Matthieu
4

Sprawdziłem twoje odpowiedzi i tylko ta Stefana Reicha zadziałała dla mnie. Chociaż nie udało mi się przywrócić okna do poprzedniego stanu (zmaksymalizowane / normalne). Uważam, że ta mutacja jest lepsza:

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

To jest setStatezamiast setExtendedState.

Jarekczek
źródło
3

Najprostszy sposób, jaki znalazłem, nie ma niespójności między platformami:

setVisible (false); setVisible (true);

Bogaty
źródło
1
powoduje migotanie, prawda? ale ładne i proste :)
rogerdpack
nie działa dla mojego procesu w tle. Również okno jest białe przy pierwszym odświeżeniu, jeśli jest wywoływane z procesu pierwszego planu. Nie można używać do przechwytywania ekranu.
DragonLord
migania można uniknąć, sprawdzając, czy okno jest
oznaczone ikoną,
2

Zasady rządzące tym, co się dzieje, gdy .toFront () JFrame są takie same w systemie Windows i Linux:

-> jeśli okno istniejącej aplikacji jest aktualnie aktywnym oknem, fokus zmienia się na żądane okno -> jeśli nie, okno po prostu miga na pasku zadań

ALE :

-> nowe okna automatycznie stają się fokusem

Więc wykorzystajmy to! Chcesz przesunąć okno do przodu, jak to zrobić? Dobrze :

  1. Utwórz puste okno niecelowe
  2. Pokaż to
  3. Poczekaj, aż pojawi się na ekranie (robi to setVisible)
  4. Po wyświetleniu zażądaj fokusu dla okna, na które chcesz przenieść fokus
  5. ukryj puste okno, zniszcz je

Lub w kodzie 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);
  }
});
Krzysztof
źródło
Nie działa na Win7, oba okna migają (jeśli nie ukryję drugiego).
NateS,
Twórczy. Nie działał dla mojego procesu w tle na Win7, gdy jest objęty. Nowa rama nie wychodzi na wierzch. Starsze JDK 6u21.
DragonLord
0

W javadoc istnieje wiele zastrzeżeń dotyczących metody toFront (), które mogą powodować problem.

Ale i tak zgadnę, kiedy „miga tylko karta na pasku zadań”, czy aplikacja została zminimalizowana? Jeśli tak, może mieć zastosowanie następujący wiersz z javadoc:

„Jeśli to okno jest widoczne, przesuwa to okno na wierzch i może uczynić je oknem, na którym jest skupione”.

Brendan Cashman
źródło
0

Aby uniknąć utraty ostrości okna, gdy wraca ono do stanu widocznego po ukryciu, wystarczy:

setExtendedState(JFrame.NORMAL);

Tak jak to:

defaultItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                showWindow();
                setExtendedState(JFrame.NORMAL);
            }
});
Martin Sansone - MiOEE
źródło