2008-11-21 26 views
81

Chúng ta có một ứng dụng Java cần được đưa đến nền trước khi một cơ chế telecontrol kích hoạt một cái gì đó trong ứng dụng.Làm thế nào để mang một cửa sổ lên phía trước?

Để có được điều này, chúng tôi đã thực hiện trong được gọi là phương pháp của lớp đại diện cho khung của ứng dụng (phần mở rộng của một JFrame) sau thực hiện:

setVisible(true); 
toFront(); 

Dưới Windows XP làm việc này lần đầu tiên nó được gọi là, vào lần thứ hai chỉ có các tab trong thanh tác vụ nhấp nháy, khung không đến phía trước nữa. Cũng vậy với Win2k. Trên Vista nó có vẻ hoạt động tốt.

Bất kỳ ý tưởng nào?

+0

bạn có một mẫu cho hành vi này? – OscarRyz

+3

Câu trả lời đúng là gọi 'toFront()' trên EDT bằng cách sử dụng 'invokeLater'. Có một câu trả lời đơn giản bao gồm dưới đây, nhưng nó không phải là câu trả lời được chấp nhận. Nó hoạt động, mặc dù. Hoàn hảo. –

+0

Tôi biết điều này là cũ, nhưng điều này cũng xảy ra trên OSX – ferdil

Trả lời

62

Một giải pháp khả thi là:

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

Có lẽ một người nên bắt đầu TẤT CẢ mã UI bên trong invokeLater ở vị trí đầu tiên? ;) –

+1

Đã không hoạt động đối với tôi trong Java 7 trên KDE 4.9.5, cửa sổ sẽ vẫn ẩn bên dưới các chương trình khác. Điều đã giúp tôi thay đổi thứ tự đưa cửa sổ lên phía trước.Thay vì ẩn một cửa sổ và hiển thị cửa sổ thứ hai, hiển thị cửa sổ thứ hai và sau đó ẩn cửa sổ đầu tiên (JFrame). – Lekensteyn

+1

Làm việc với Windows 10 chạy Java 1.8 trong một applet – Elliott

0

Có rất nhiều caveats trong javadoc cho phương thức toFront() có thể gây ra sự cố của bạn.

Nhưng tôi sẽ đoán, khi "chỉ tab trong thanh tác vụ nhấp nháy", ứng dụng có được giảm thiểu không? Nếu như vậy dòng sau từ javadoc có thể áp dụng:

"Nếu cửa sổ này hiển thị, hãy đưa Window này lên phía trước và có thể làm cho cửa sổ tập trung."

20

Windows có cơ sở để ngăn cửa sổ lấy cắp tiêu điểm; thay vào đó nó nhấp nháy biểu tượng trên thanh tác vụ. Trong XP nó là theo mặc định (nơi duy nhất tôi đã nhìn thấy để thay đổi nó là sử dụng TweakUI, nhưng có một thiết lập registry ở đâu đó). Trong Vista, họ có thể đã thay đổi mặc định và/hoặc hiển thị nó dưới dạng cài đặt có thể truy cập của người dùng với giao diện người dùng ngoài hộp.

Ngăn cửa sổ tự buộc mình ở phía trước và lấy nét là một tính năng kể từ Windows 2K (và tôi, vì một, rất biết ơn vì nó).

Điều đó nói rằng, tôi có một ứng dụng Java nhỏ tôi sử dụng để nhắc nhở tôi ghi lại các hoạt động của mình trong khi làm việc, và nó tự làm cho cửa sổ hoạt động sau mỗi 30 phút (có thể cấu hình, tất nhiên). Nó luôn hoạt động liên tục trong Windows XP và không bao giờ nhấp nháy cửa sổ thanh tiêu đề. Nó sử dụng đoạn mã sau, được gọi là trong thread UI như là kết quả của một bắn hẹn giờ sự kiện:

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

(dòng đầu tiên khôi phục lại nếu giảm thiểu ... thực sự nó sẽ khôi phục lại nó nếu tối đa quá, nhưng tôi không bao giờ có nó như vậy).

Trong khi tôi thường có ứng dụng này được thu nhỏ, thường thì nó chỉ đơn giản là phía sau trình soạn thảo văn bản của tôi. Và, như tôi đã nói, nó luôn hoạt động.

Tôi có ý tưởng về vấn đề của bạn có thể là gì - có lẽ bạn có điều kiện chủng tộc với cuộc gọi setVisible(). toFront() có thể không hợp lệ trừ khi cửa sổ được hiển thị thực sự khi nó được gọi; Tôi đã gặp vấn đề này với requestFocus() trước đây. Bạn có thể cần phải thực hiện cuộc gọi toFront() trong trình nghe UI trên một sự kiện kích hoạt cửa sổ.

2014-09-07: Tại một số điểm trong thời gian mã trên ngừng làm việc, có lẽ tại Java 6 hoặc 7. Sau một số cuộc điều tra và thử nghiệm tôi đã phải cập nhật mã để ghi đè phương pháp của cửa sổ toFront làm điều này (cùng với mã được sửa đổi từ những gì ở trên):

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

Vì Java 8_20, mã này có vẻ hoạt động tốt.

+1

+1 để hỗ trợ không cho phép cửa sổ lấy nét. Tôi ghét khi điều đó xảy ra khi tôi nhập một tài liệu. –

+1

Tôi hoàn toàn đồng ý với bạn chống lại việc lấy cắp tiêu điểm, nhưng trong trường hợp chính xác này, người dùng mong đợi ứng dụng sẽ đến trước. Nhưng nó sẽ uncool để thay đổi các thiết lập registry và thay đổi hành vi cửa sổ hoàn chỉnh. – boutta

+0

Tôi đoán 'super.setAlwaysOnTop (false);' là để cửa sổ không phải là * luôn luôn * trên đầu trang, điều cần thiết để loại bỏ 'true' mà chúng ta đã đặt trước đó để đưa cửa sổ lên phía trước, chính xác? Tôi hỏi vì với mã của bạn, cửa sổ vẫn luôn ở trên cùng trong trường hợp của tôi, điều mà tôi rõ ràng không muốn. Chạy jre1.8.0_66 trên Windows 10. –

33

tôi đã cùng một vấn đề với việc đưa một JFrame vào phía trước dưới Ubuntu (Java 1.6.0_10). Và cách duy nhất tôi có thể giải quyết nó là cung cấp WindowListener. Cụ thể, tôi phải đặt số JFrame của mình để luôn ở trên đầu bất cứ khi nào toFront() được gọi và cung cấp windowDeactivated trình xử lý sự kiện cho setAlwaysOnTop(false).


Vì vậy, đây là mã có thể được đặt vào cơ sở JFrame, được sử dụng để lấy tất cả các khung ứng dụng.

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

Bất cứ khi nào khung của bạn sẽ được hiển thị hoặc được chuyển đến cuộc gọi trước frame.setVisible(true).

Vì tôi đã chuyển sang Ubuntu 9,04, có vẻ như không cần phải có số WindowListener để gọi super.setAlwaysOnTop(false) - như có thể quan sát được; mã này đã được chuyển sang phương thức toFront()setVisible().

Xin lưu ý rằng phương pháp setVisible() phải luôn được gọi trên EDT.

+1

Làm việc trong mọi hoàn cảnh, vì vậy tôi chấp nhận điều này. – boutta

+0

Cảm ơn! Cũng có liên quan là câu hỏi này: http://stackoverflow.com/questions/2315560/how-do-you-force-a-java-swt-program-to-move-itself-to-the-foreground – rogerdpack

+0

Nó doesn ' t biên dịch bởi tôi vì phương thức setDisposed(). Không thể tìm thấy. – ka3ak

2

Cách đơn giản nhất tôi đã phát hiện ra rằng không có mâu thuẫn trên nền tảng:

setVisible (false); setVisible (true);

+1

gây ra một số nhấp nháy mặc dù nó không? tốt đẹp và đơn giản mặc dù :) – rogerdpack

+0

đã không làm việc cho quá trình nền của tôi. Ngoài ra cửa sổ đi lên màu trắng cho lần làm mới đầu tiên nếu được gọi từ quá trình tiền cảnh. Không thể sử dụng để lấy màn hình. – DragonLord

+0

nhấp nháy có thể tránh được bằng cách kiểm tra xem cửa sổ có được biểu tượng hóa hay không – totaam

4

phương pháp đơn giản này đã làm việc cho tôi một cách hoàn hảo trong Windows 7:

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

'repaint()' là không cần thiết, 'invokeLater()' đã làm điều đó. Cảm ơn bạn. – Matthieu

2

Các quy tắc chi phối những gì xảy ra khi bạn .toFront() một JFrame đều giống nhau trong các cửa sổ và trong linux:

-> nếu cửa sổ của ứng dụng hiện tại hiện là cửa sổ tập trung, sau đó tập trung hoán đổi sang cửa sổ được yêu cầu -> nếu không, cửa sổ chỉ nhấp nháy trên thanh tác vụ

NHƯNG:

-> cửa sổ mới tự động lấy tiêu điểm

Vì vậy, hãy khai thác điều này! Bạn muốn mang một cửa sổ về phía trước, làm thế nào để làm điều đó? Vâng:

  1. Tạo một cửa sổ phi mục đích trống
  2. Hiện nó
  3. Chờ cho nó để hiển thị trên màn hình (setVisible nào đó)
  4. Khi hiển thị, yêu cầu tập trung cho các cửa sổ bạn thực sự muốn để mang lại sự tập trung để
  5. ẩn cửa sổ trống rỗng, tiêu diệt nó

Hoặc, trong mã 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); 
    } 
}); 
+0

Không hoạt động trên Win7, cả hai cửa sổ flash (nếu tôi không ẩn thứ 2). – NateS

+0

Quảng cáo. Đã không làm việc cho quá trình nền của tôi trên Win7, khi được bảo hiểm. Khung hình mới không xuất hiện trên đầu trang. JDK 6u21 cũ hơn. – DragonLord

5

Hj, tất cả các phương pháp của bạn đều không hoạt động đối với tôi, trong Fedora KDE 14. Tôi có một cách dơ bẩn để đưa một cửa sổ lên phía trước, trong khi chúng tôi đang chờ Oracle khắc phục vấn đề này.

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

    //... 

} 

Và, công trình này một cách hoàn hảo trong Fedora KDE 14 :-) tôi

+0

Một chút hacky, làm việc cho chúng tôi, nhưng chỉ cho cuộc gọi đầu tiên :-). (Kubuntu 12.04) - giải pháp khác đã thất bại – user85155

+0

Đây là giải pháp duy nhất làm việc cho tôi (Windows Server 2012 R2) cho một vấn đề mà một JFrame (đăng nhập) được mở nhưng không tập trung cho đến khi người dùng nhấp vào nó. – glenneroo

11

Dưới đây là một phương pháp mà thực sự hoạt động (thử nghiệm trên Windows Vista): D

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

Biến toàn màn hình chỉ ra nếu bạn muốn ứng dụng chạy toàn màn hình hoặc cửa sổ.

Điều này không làm sáng thanh tác vụ, nhưng đưa cửa sổ lên phía trước một cách đáng tin cậy.

+0

Cảm ơn mẹo setExtendedState. Tôi đã sử dụng nó cùng với giải pháp toFront() và repaint() để đưa cửa sổ lên nền trước ngay cả khi nó được thu nhỏ. – rob

+1

Đã xác nhận: giải pháp này hoạt động trong WindowsXP, sử dụng kết quả đầu tiên trong thông báo nhấp nháy trong thanh tác vụ. Cảm ơn! –

3

Tôi đã kiểm tra câu trả lời của bạn và chỉ Stefan Reich's one làm việc cho tôi. Mặc dù tôi không thể quản lý để khôi phục lại cửa sổ về trạng thái trước đó của nó (tối đa/bình thường). Tôi tìm thấy đột biến này tốt hơn:

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

Đó là setState thay vì setExtendedState.

0

Để tránh cửa sổ mất tập trung khi trở về nó để có thể nhìn thấy sau khi bị giấu tất cả những gì cần thiết là:

setExtendedState(JFrame.NORMAL); 

Giống như vậy:

defaultItem.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
       showWindow(); 
       setExtendedState(JFrame.NORMAL); 
      } 
}); 
Các vấn đề liên quan