Come portare una finestra in primo piano?

Abbiamo un’applicazione Java che deve essere portata in primo piano quando un meccanismo di telecontrollo triggers qualcosa nell’applicazione.

Per ottenere ciò, ci siamo resi conto del metodo chiamato della class che rappresenta il frame della nostra applicazione (estensione di un JFrame ) dopo l’implementazione:

 setVisible(true); toFront(); 

Sotto Windows XP, questo funziona la prima volta che viene chiamato, la seconda volta solo la scheda nella barra delle applicazioni lampeggia, il frame non viene più in primo piano. Lo stesso vale per Win2k. Su Vista sembra funzionare bene.

Hai qualche idea?

Una ansible soluzione è:

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

Ho avuto lo stesso problema nel portare un JFrame in primo piano con Ubuntu (Java 1.6.0_10). E l’unico modo per risolverlo è fornire un WindowListener . Nello specifico, ho dovuto impostare il mio JFrame per rimanere sempre in primo piano ogni volta che viene invocato toFront() e fornire il gestore di eventi setAlwaysOnTop(false) a setAlwaysOnTop(false) .


Quindi, ecco il codice che potrebbe essere inserito in una base JFrame , che viene utilizzata per derivare tutti i frame dell’applicazione.

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

Ogni volta che il frame deve essere visualizzato o portato in front frame.setVisible(true) .

Da quando mi sono trasferito su Ubuntu 9.04 non sembra esserci alcuna necessità di avere un WindowListener per invocare super.setAlwaysOnTop(false) – come si può osservare; questo codice è stato spostato sui metodi toFront() e setVisible() .

Si noti che il metodo setVisible() deve sempre essere invocato su EDT.

Windows ha la possibilità di impedire che Windows torni a fuoco; invece lampeggia l’icona della barra delle applicazioni. In XP è attivo per impostazione predefinita (l’unico posto che ho visto per cambiarlo è l’utilizzo di TweakUI, ma c’è un’impostazione di registro da qualche parte). In Vista potrebbero aver cambiato l’impostazione predefinita e / o esposta come impostazione accessibile all’utente con l’interfaccia utente predefinita.

Impedire a Windows di forzare se stessi in primo piano e concentrarsi è una funzione da quando Windows 2K (e io, per esempio, sono grato per questo).

Detto questo, ho una piccola app Java che uso per ricordarmi di registrare le mie attività mentre lavoro, e si fa la finestra triggers ogni 30 minuti (configurabile, ovviamente). Funziona sempre in modo coerente in Windows XP e non lampeggia mai la finestra della barra del titolo. Utilizza il seguente codice, chiamato nel thread dell’interfaccia utente come risultato di un evento di triggerszione timer:

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

(la prima riga ripristina se minimizzata … effettivamente la ripristinerebbe se ingrandita troppo, ma non l’ho mai così).

Mentre di solito ho questa app ridotta al minimo, molto spesso è semplicemente dietro il mio editor di testo. E, come ho detto, funziona sempre.

Ho un’idea su quale potrebbe essere il tuo problema – forse hai una race condition con la chiamata setVisible (). toFront () potrebbe non essere valido a meno che la finestra non sia effettivamente visualizzata quando viene chiamata; Ho avuto questo problema con requestFocus () prima. Potrebbe essere necessario inserire la chiamata toFront () in un listener dell’interfaccia utente in un evento triggersto dalla finestra.

2014-09-07: Ad un certo punto nel tempo il codice sopra ha smesso di funzionare, forse su Java 6 o 7. Dopo alcune indagini e sperimentazioni ho dovuto aggiornare il codice per scavalcare il metodo toFront della finestra, fare questo (insieme al codice modificato da cosa c’è sopra):

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

A partire da Java 8_20, questo codice sembra funzionare correttamente.

Ecco un metodo che funziona VERAMENTE (testato su Windows Vista): D

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

La variabile a schermo intero indica se desideri che l’app venga eseguita a schermo intero o a windows.

Questo non lampeggia la barra delle applicazioni, ma porta la finestra in modo affidabile.

H, tutti i tuoi metodi non funzionano per me, in Fedora KDE 14. Ho un modo osceno per portare una finestra in primo piano, mentre stiamo aspettando che Oracle risolva questo problema.

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

E, questo funziona perfettamente con Fedora KDE 14 🙂

Questo semplice metodo ha funzionato perfettamente con Windows 7:

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

Ho trovato il modo più semplice per non avere incoerenza tra le piattaforms:

setVisible (false); setVisible (true);

Ho provato le tue risposte e solo quella di Stefan Reich ha funzionato per me. Anche se non sono riuscito a ripristinare la finestra al suo stato precedente (massimizzato / normale). Ho trovato questa mutazione migliore:

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

Questo è setState invece di setExtendedState .

Le regole che regolano ciò che accade quando tu .toFront () un JFrame sono le stesse in windows e in linux:

-> se una finestra dell’applicazione esistente è attualmente la finestra focalizzata, quindi triggers lo scambio nella finestra richiesta -> in caso contrario, la finestra lampeggia semplicemente nella barra delle applicazioni

MA :

-> le nuove windows si triggersno automaticamente

Quindi sfruttiamo questo! Vuoi portare una finestra in primo piano, come si fa? Bene :

  1. Crea una finestra vuota non valida
  2. Mostralo
  3. Attendi che venga visualizzato sullo schermo (setVisible lo fa)
  4. Quando viene mostrato, richiedi il focus per la finestra a cui vuoi effettivamente focalizzare l’attenzione
  5. nascondi la finestra vuota, distruggila

Oppure, nel codice 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); } }); 

Ci sono numerosi avvertimenti nel javadoc per il metodo toFront () che potrebbe causare il tuo problema.

Ma indovinerò comunque, quando “solo la scheda nella barra delle applicazioni lampeggia”, l’applicazione è stata ridotta a icona? In tal caso, si può applicare la seguente riga di javadoc:

“Se questa finestra è visibile, porta questa finestra in primo piano e potrebbe renderla la finestra focalizzata”.

Per evitare che la finestra perdi lo stato attivo quando torna a essere visibile dopo essere stata nascosta, tutto ciò che è necessario è:

 setExtendedState(JFrame.NORMAL); 

Così:

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