Bagaimana cara membawa jendela ke depan?

90

Kami memiliki aplikasi Java yang perlu dibawa ke latar depan saat mekanisme telekontrol mengaktifkan sesuatu dalam aplikasi.

Untuk mendapatkan ini, kami telah menyadari dalam metode yang dipanggil kelas yang mewakili kerangka aplikasi kami (ekstensi a JFrame) implementasi berikut:

setVisible(true);
toFront();

Di bawah Windows XP, ini berfungsi saat pertama kali dipanggil, pada kedua kalinya hanya tab di bilah tugas yang berkedip, bingkai tidak muncul lagi ke depan. Hal yang sama berlaku untuk Win2k. Di Vista tampaknya berfungsi dengan baik.

Apakah kamu punya ide

pertarungan
sumber
apakah Anda memiliki contoh untuk perilaku ini?
OscarRyz
3
Jawaban yang tepat adalah memanggil toFront()EDT menggunakan invokeLater. Ada jawaban sederhana yang disertakan di bawah ini, tetapi itu bukan jawaban yang diterima. Itu berhasil. Sempurna.
Erick Robertson
Saya tahu ini sudah lama, tetapi ini juga terjadi di OSX
ferdil
Saya mengalami masalah ini, tetapi tidak ada jawaban di bawah yang dapat menyelesaikannya. Saya yakin ini disebabkan oleh jendela yang tidak mengizinkan saya untuk 'Mencuri' Fokus untuk jendela pertama saya dalam aplikasi.
Craig Warren

Jawaban:

69

Solusi yang mungkin adalah:

java.awt.EventQueue.invokeLater(new Runnable() {
    @Override
    public void run() {
        myFrame.toFront();
        myFrame.repaint();
    }
});
sth
sumber
8
Mungkin seseorang harus memulai SEMUA kode UI di dalam invokeLater di tempat pertama? ;)
java.is.for.desktop.indeed
2
Tidak berhasil untuk saya di Java 7 pada KDE 4.9.5, jendela akan tetap bersembunyi di bawah program lain. Yang membantu saya adalah mengubah urutan membawa jendela ke depan. Alih-alih menyembunyikan satu jendela dan menampilkan jendela kedua, tunjukkan jendela kedua dan kemudian sembunyikan jendela pertama (JFrame).
Lekensteyn
1
Bekerja dengan Windows 10 yang menjalankan Java 1.8 dalam applet
Elliott
Apa yang akan menjadi metode kebalikannya?
Kardinal - Kembalikan Monica
33

Saya memiliki masalah yang sama dengan membawa a JFrameke depan di bawah Ubuntu (Java 1.6.0_10). Dan satu-satunya cara saya bisa mengatasinya adalah dengan menyediakan file WindowListener. Secara khusus, saya harus mengatur agar saya JFrameselalu berada di atas setiap kali toFront()dipanggil, dan menyediakan windowDeactivatedpengendali acara setAlwaysOnTop(false).


Jadi, berikut adalah kode yang dapat ditempatkan ke dalam basis JFrame, yang digunakan untuk mendapatkan semua bingkai aplikasi.

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

Kapan pun bingkai Anda harus ditampilkan atau dibawa ke depan frame.setVisible(true).

Sejak saya pindah ke Ubuntu 9.04, tampaknya tidak perlu memiliki WindowListeneruntuk pemanggilan super.setAlwaysOnTop(false)- seperti yang dapat diamati; kode ini dipindahkan ke metode toFront()dan setVisible().

Harap dicatat bahwa metode setVisible()harus selalu dipanggil di EDT.

01es
sumber
Terima kasih! Yang juga terkait adalah pertanyaan ini: stackoverflow.com/questions/2315560/…
rogerdpack
Itu tidak dikompilasi oleh saya karena metode setDisposed (). Tidak dapat ditemukan.
ka3ak
1
@ ka3ak Ini adalah setter terproteksi yang dapat diperkenalkan pada kelas berbasis JFrame yang disarankan untuk melacak situasi dengan frame yang dibuang. Metode dispose () perlu diganti dengan panggilan ke setDisposed (true). Ini tidak sepenuhnya diperlukan untuk semua orang.
01es
1
Itu .setAlwaysOnTop(true);adalah satu-satunya yang berhasil untuk saya saat menggunakan JWindow.
DGolberg
setAlwaysOnTop(true)adalah satu-satunya cara saya menjalankannya di bawah windows 10 - terima kasih!
Hartmut P.
23

Windows memiliki fasilitas untuk mencegah jendela mencuri fokus; sebagai gantinya, ikon taskbar berkedip. Di XP, ini aktif secara default (satu-satunya tempat yang saya lihat untuk mengubahnya adalah menggunakan TweakUI, tetapi ada pengaturan registri di suatu tempat). Di Vista mereka mungkin telah mengubah default dan / atau mengeksposnya sebagai pengaturan yang dapat diakses pengguna dengan UI out-of-the-box.

Mencegah jendela memaksakan diri ke depan dan mengambil fokus adalah fitur sejak Windows 2K (dan saya, untuk satu, berterima kasih untuk itu).

Meskipun demikian, saya memiliki sedikit aplikasi Java yang saya gunakan untuk mengingatkan saya merekam aktivitas saya saat bekerja, dan itu membuat jendela aktif setiap 30 menit (dapat dikonfigurasi, tentu saja). Itu selalu bekerja secara konsisten di bawah Windows XP dan tidak pernah mem-flash jendela bilah judul. Ini menggunakan kode berikut, yang dipanggil di thread UI sebagai hasil dari pengaktifan peristiwa timer:

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

(baris pertama mengembalikan jika diminimalkan ... sebenarnya itu akan mengembalikannya jika dimaksimalkan juga, tapi saya tidak pernah memilikinya).

Meskipun saya biasanya memiliki aplikasi ini diminimalkan, cukup sering itu hanya di belakang editor teks saya. Dan, seperti yang saya katakan, itu selalu berhasil.

Saya memiliki ide tentang apa masalah Anda - mungkin Anda memiliki kondisi balapan dengan panggilan setVisible (). toFront () mungkin tidak valid kecuali jika jendela benar-benar ditampilkan saat dipanggil; Saya pernah mengalami masalah ini dengan requestFocus () sebelumnya. Anda mungkin perlu menempatkan panggilan toFront () di pendengar UI pada peristiwa jendela yang diaktifkan.

2014-09-07: Pada suatu saat kode di atas berhenti bekerja, mungkin di Java 6 atau 7. Setelah beberapa penyelidikan dan eksperimen, saya harus memperbarui kode untuk mengganti metode jendela toFrontlakukan ini (sehubungan dengan kode yang dimodifikasi dari apa di atas):

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

Pada Java 8_20, kode ini tampaknya berfungsi dengan baik.

Lawrence Dol
sumber
1
1 untuk mendukung tidak membiarkan jendela mencuri fokus. Saya benci jika itu terjadi saat saya mengetik di dokumen.
Ken Paul
1
Saya sepenuhnya setuju dengan Anda untuk tidak mencuri fokus, tetapi dalam kasus ini, pengguna mengharapkan aplikasi tersebut muncul di depan. Tetapi tidak keren untuk mengubah pengaturan registri dan mengubah perilaku windows secara lengkap.
tentang
Saya menduga super.setAlwaysOnTop(false);ini adalah agar jendela tidak selalu di atas, yang diperlukan untuk menyingkirkan yang truekita atur sebelumnya untuk membawa jendela ke depan, bukan? Saya bertanya karena dengan kode Anda jendela masih selalu di atas dalam kasus saya, yang jelas tidak saya inginkan. Menjalankan jre1.8.0_66 di Windows 10.
Bram Vanroy
@Bram: Ya itu benar. Saya menjalankan kode pada versi Java dan Windows yang sama dan tidak selalu berakhir di atas jendela lain. Mungkin tidak perlu untuk selalu mengatur di atas, tetapi saya pikir sebaliknya Windows hanya mem-flash bilah judul, setidaknya dalam beberapa kondisi.
Lawrence Dol
Hm, aneh. Bisakah Anda melihat pertanyaan serupa yang saya tautkan ke jawaban ini? Mungkin kode itu menunjukkan masalah dengan lebih jelas: stackoverflow.com/questions/34637597/…
Bram Vanroy
11

Berikut adalah metode yang BENAR-BENAR berfungsi (diuji pada Windows Vista): D

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

Variabel layar penuh menunjukkan apakah Anda ingin aplikasi berjalan dalam layar penuh atau dalam jendela.

Ini tidak mem-flash bilah tugas, tetapi membawa jendela ke depan dengan andal.

Stefan Reich
sumber
Terima kasih atas tip setExtendedState. Saya menggunakannya bersama dengan solusi toFront () dan repaint () untuk membawa jendela ke latar depan bahkan jika itu diminimalkan.
merampok
1
Dikonfirmasi: solusi ini berfungsi di WindowsXP, menggunakan toFront menghasilkan pesan berkedip di bilah tugas. Terima kasih!
Eric Lindauer
5

Hj, semua metode Anda tidak berfungsi untuk saya, di Fedora KDE 14. Saya memiliki cara kotor untuk membawa jendela ke depan, sementara kami menunggu Oracle untuk memperbaiki masalah ini.

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

  //...

}

Dan, ini bekerja dengan sempurna di Fedora KDE 14 saya :-)


sumber
Sedikit hacky, berfungsi untuk kami, tetapi hanya untuk panggilan pertama :-). (Kubuntu 12.04) - solusi lain gagal
user85155
Ini adalah satu-satunya solusi yang berhasil untuk saya (Windows Server 2012 R2) untuk masalah di mana JFrame (login) dibuka tetapi tidak memiliki fokus hingga pengguna mengkliknya.
glenneroo
4

Metode sederhana ini bekerja untuk saya dengan sempurna di Windows 7:

    private void BringToFront() {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                if(jFrame != null) {
                    jFrame.toFront();
                    jFrame.repaint();
                }
            }
        });
    }
Tuan Ed
sumber
2
Tidak repaint()perlu, yang invokeLater()melakukannya. Terima kasih.
Matthieu
4

Saya menguji jawaban Anda dan hanya jawaban Stefan Reich yang berhasil untuk saya. Meskipun saya tidak dapat memulihkan jendela ke keadaan sebelumnya (dimaksimalkan / normal). Saya menemukan mutasi ini lebih baik:

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

Itu setStatebukan setExtendedState.

Jarekczek
sumber
3

Cara termudah yang saya temukan yang tidak memiliki ketidakkonsistenan di seluruh platform:

setVisible (false); setVisible (true);

Kaya
sumber
1
menyebabkan beberapa berkedip meskipun bukan? bagus dan sederhana :)
rogerdpack
tidak bekerja untuk proses latar belakang saya. Jendela juga muncul putih untuk penyegaran pertama jika dipanggil dari proses latar depan. Tidak dapat digunakan untuk perebutan layar.
DragonLord
berkedip dapat dihindari dengan memeriksa apakah jendela diikonkan atau tidak
totaam
2

Aturan yang mengatur apa yang terjadi ketika Anda .toFront () a JFrame sama di windows dan di linux:

-> jika jendela aplikasi yang ada saat ini merupakan jendela fokus, maka fokus beralih ke jendela yang diminta -> jika tidak, jendela hanya berkedip di bilah tugas

TAPI:

-> jendela baru secara otomatis mendapatkan fokus

Jadi mari kita manfaatkan ini! Anda ingin membawa jendela ke depan, bagaimana cara melakukannya? Nah:

  1. Buat jendela non-tujuan kosong
  2. Tunjukkan
  3. Tunggu hingga muncul di layar (setVisible melakukan itu)
  4. Saat diperlihatkan, minta fokus untuk jendela yang sebenarnya Anda inginkan untuk dijadikan fokus
  5. sembunyikan jendela kosong, hancurkan

Atau, dalam kode 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);
  }
});
Christopher
sumber
Tidak berfungsi di Win7, kedua windows berkedip (jika saya tidak menyembunyikan yang ke-2).
NateS
Kreatif. Tidak berfungsi untuk proses latar belakang saya di Win7, saat ditutupi. Bingkai baru tidak muncul di atas. JDK 6u21 yang lebih lama.
DragonLord
0

Ada banyak peringatan dalam javadoc untuk metode toFront () yang mungkin menyebabkan masalah Anda.

Tetapi saya akan tetap menebak, ketika "hanya tab di bilah tugas yang berkedip", apakah aplikasi telah diminimalkan? Jika demikian, baris berikut dari javadoc mungkin berlaku:

"Jika Jendela ini terlihat, bawa Jendela ini ke depan dan dapat menjadikannya Jendela yang terfokus."

Brendan Cashman
sumber
0

Untuk menghindari jendela kehilangan fokus saat kembali terlihat setelah disembunyikan, yang diperlukan hanyalah:

setExtendedState(JFrame.NORMAL);

Seperti:

defaultItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                showWindow();
                setExtendedState(JFrame.NORMAL);
            }
});
Martin Sansone - MiOEE
sumber