2010-04-05 32 views
12

Tôi có một cửa sổ bật lên được hiển thị khi người dùng nhấp vào nút. Tôi muốn ẩn cửa sổ bật lên khi bất kỳ sự kiện nào sau đây xảy ra:Làm cách nào để ẩn một cửa sổ bật lên khi bạn nhấp vào một nơi khác

  1. Người dùng nhấp vào một nơi khác trong ứng dụng. (Ví dụ: bảng điều khiển nền)
  2. Người dùng thu nhỏ ứng dụng.

JPopupMenu có hành vi này, nhưng tôi cần nhiều hơn JMenuItems. Khối mã sau đây là một minh họa đơn giản để chứng minh việc sử dụng hiện tại.

import java.awt.*; 
import java.awt.event.ActionEvent; 
import javax.swing.*; 

public class PopupTester extends JFrame { 
    public static void main(String[] args) { 
    final PopupTester popupTester = new PopupTester(); 
    popupTester.setLayout(new FlowLayout()); 
    popupTester.setSize(300, 100); 
    popupTester.add(new JButton("Click Me") { 
     @Override 
     protected void fireActionPerformed(ActionEvent event) { 
     Point location = getLocationOnScreen(); 
      int y = (int) (location.getY() + getHeight()); 
      int x = (int) location.getX(); 
      JLabel myComponent = new JLabel("Howdy"); 
      Popup popup = PopupFactory.getSharedInstance().getPopup(popupTester, myComponent, x, y); 
      popup.show(); 
     } 
     }); 
     popupTester.add(new JButton("No Click Me")); 
     popupTester.setVisible(true); 
     popupTester.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    } 
} 

Trả lời

6

Như pajton đã lưu ý trong một nhận xét trước, Popup không phải là JComponent mà người nghe có thể dễ dàng bị ràng buộc. Tuy nhiên, như các trạng thái tài liệu của nó, "việc triển khai Popup có trách nhiệm tạo và duy trì các thành phần của riêng chúng để hiển thị [chủ đề của nó] cho người dùng."

Vì vậy, khi sử dụng cơ chế này làm cơ chế trình bày, Popup của bạn sẽ phải tự trình bày dưới dạng thành phần Swing thực tế anyway. Hãy đăng ký chính nó cho thành phần đó. Tự ẩn nó khi thành phần mất tiêu điểm.

import java.awt.FlowLayout; 
import java.awt.Frame; 
import java.awt.Point; 
import java.awt.event.ActionEvent; 
import java.awt.event.WindowEvent; 
import java.awt.event.WindowFocusListener; 
import javax.swing.JButton; 
import javax.swing.JDialog; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JOptionPane; 
import javax.swing.Popup; 

public class PopupTester extends JFrame { 
    private static class MessagePopup extends Popup 
     implements WindowFocusListener 
    { 
     private final JDialog dialog; 

     public MessagePopup(Frame base, String message) { 
      super(); 
      dialog = new JOptionPane().createDialog(base, "Message"); 
      dialog.setModal(false); 
      dialog.setContentPane(new JLabel(message)); 
     } 
     @Override public void show() { 
      dialog.addWindowFocusListener(this); 
      dialog.setVisible(true); 
     } 
     @Override public void hide() { 
      dialog.setVisible(false); 
      dialog.removeWindowFocusListener(this); 
     } 
     public void windowGainedFocus(WindowEvent e) { 
      // NO-OP 
     } 

     public void windowLostFocus(WindowEvent e) { 
      hide(); 
     } 
    } 

    public static void main(String[] args) { 
    final PopupTester popupTester = new PopupTester(); 
    popupTester.setLayout(new FlowLayout()); 
    popupTester.setSize(300, 100); 
    popupTester.add(new JButton("Click Me") { 
     @Override 
     protected void fireActionPerformed(ActionEvent event) { 
     Point location = getLocationOnScreen(); 
      MessagePopup popup = new MessagePopup(popupTester, "Howdy"); 
      popup.show(); 
     } 
     }); 
     popupTester.add(new JButton("No Click Me")); 
     popupTester.setVisible(true); 
     popupTester.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    } 
} 
+0

Đây là một giải pháp tốt. Thêm giao diện WindowFocusListener vào Popup thực hiện thủ thuật. Tôi đã kết thúc bằng cách sử dụng một JWindow thay vì một JDialog bởi vì tôi không muốn trang trí cửa sổ. Tôi sẽ đăng giải pháp cuối cùng. –

2

Bạn có thể thêm MouseListener vào bảng điều khiển nền và ẩn cửa sổ bật lên khi ai đó nhấp vào bảng điều khiển.

Để phản ứng khi giảm thiểu ứng dụng, hãy sử dụng WindowListener được đính kèm với JFrame.

Vv, v.v. Có vẻ như tẻ nhạt, nhưng chắc chắn sẽ hoạt động.

+0

Đề xuất tốt. Điều này trở nên khó khăn với một ứng dụng lớn vì tôi không thể thêm một MouseListener vào mọi thành phần trên màn hình. –

+0

Thật đáng tiếc là bản thân 'Popup' không phải là' JComponent'. Sau đó, bạn có thể đính kèm một số người nghe để nắm bắt các sự kiện khi nó mất tiêu điểm. Có thể xem xét sử dụng 'JDialog' và sau đó chỉ đơn giản là' MouseListener' và phương thức 'mouseExited()' của nó. – pajton

+0

JDialog đi kèm với hành lý trang trí cửa sổ. Tôi đã có thể thử một cái gì đó lên mà sử dụng JWindow nhưng có một tấn xử lý sự kiện thủ công và nó vẫn kết thúc khá kỳ quặc. Popup có thực sự bị phá vỡ về cơ bản mà nó không thể hỗ trợ một cái gì đó như thế này? –

10

Sử dụng JPopupMenu. Bạn có thể thêm bất kỳ thành phần nào vào nó, không chỉ các mục menu.

+3

Tôi cũng có thể sử dụng phương pháp này. Nó kết thúc được đơn giản hơn nhiều. Rõ ràng là hành vi ẩn đi khi menu mất tiêu điểm chỉ hoạt động khi bạn vượt qua khung chính với tư cách người gọi trên phương thức show(). Nếu bạn sử dụng setVisible (true), bạn sẽ không nhận được hành vi mong muốn. –

+2

Tôi cũng làm điều này thường xuyên. Chỉ cần đặt bố cục của JPopupMenu thành BorderLayout và thêm nội dung của bạn với ràng buộc CENTER. JPopupMenu không có vấn đề hiển thị nội dung xoay tùy ý. – CarlG

+0

Tôi đã thử nhiều thái độ hơn (JDialog không biên giới, javax.swing.Popup) và điều này có vẻ là giải pháp tốt nhất. –

1

Bạn có thể thêm FocusListener vào cửa sổ bật lên và bỏ nó khi nó mất tiêu điểm. Tuy nhiên, điều đó sẽ gây ra cho bạn một số rắc rối khi mất tập trung là do một số ứng dụng khác (cửa sổ mới đến nền trước, bạn chuyển máy ảo, v.v.)

Nhưng có lẽ bạn (a) biết rằng điều đó không thể xảy ra trường hợp của bạn hoặc (b) sẽ muốn đóng cửa sổ bật lên trong các trường hợp như vậy anyway, một cách tiếp cận tập trung dựa trên vẫn có thể là thú vị cho bạn.

2

Cảm ơn pajton và Noel Ang đã khiến tôi chỉ đúng hướng! Đây là giải pháp mà tôi đã kết thúc. Tôi chỉ bao gồm nó ở đây để những người khác có thể hưởng lợi từ nó.

Tôi đã kết thúc với một JWindow vì nó không nhận được trang trí cửa sổ nhưng không nhận được sự kiện tập trung.

import java.awt.*; 
import java.awt.event.*; 

import javax.swing.*; 

public class PopupTester extends JFrame { 
    private static class MessagePopup extends Popup implements WindowFocusListener { 
    private final JWindow dialog; 

    public MessagePopup(Frame base, JLabel component, int x, int y) { 
     super(); 
     dialog = new JWindow(base); 
     dialog.setFocusable(true); 
     dialog.setLocation(x, y); 
     dialog.setContentPane(component); 
     component.setBorder(new JPopupMenu().getBorder()); 
     dialog.setSize(component.getPreferredSize()); 
     dialog.addKeyListener(new KeyAdapter() { 
     @Override 
     public void keyPressed(KeyEvent e) { 
      if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { 
      dialog.setVisible(false); 
      } 
     } 
     }); 
    } 

    @Override 
    public void show() { 
     dialog.addWindowFocusListener(this); 
     dialog.setVisible(true); 
    } 

    @Override 
    public void hide() { 
     dialog.setVisible(false); 
     dialog.removeWindowFocusListener(this); 
    } 

    public void windowGainedFocus(WindowEvent e) { 
     // NO-OP 
    } 

    public void windowLostFocus(WindowEvent e) { 
     hide(); 
    } 
    } 

    public static void main(String[] args) { 
    final PopupTester popupTester = new PopupTester(); 
    popupTester.setLayout(new FlowLayout()); 
    popupTester.setSize(300, 100); 
    popupTester.add(new JButton("Click Me") { 
     @Override 
     protected void fireActionPerformed(ActionEvent event) { 
     Point location = getLocationOnScreen(); 
     int x = (int) location.getX(); 
     int y = (int) (location.getY() + getHeight()); 
     JLabel myComponent = new JLabel("Howdy"); 

     MessagePopup popup = new MessagePopup(popupTester, myComponent, x, y); 
     popup.show(); 
     } 
    }); 
    popupTester.add(new JButton("No Click Me")); 
    popupTester.setVisible(true); 
    popupTester.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    } 
} 
Các vấn đề liên quan