2010-04-05 18 views
12

Mam wyskakujące okienko, które jest wyświetlane, gdy użytkownik kliknie przycisk. Chciałbym ukryć wyskakujące okienko, gdy wystąpi jedno z następujących zdarzeń:Jak ukryć wyskakujące okienko, gdy klikniesz gdzieś indziej?

  1. Użytkownik klika gdziekolwiek indziej w aplikacji. (Na przykład panel tła)
  2. Użytkownik minimalizuje aplikację.

JPopupMenu ma to zachowanie, ale potrzebuję czegoś więcej niż tylko JMenuItems. Poniższy blok kodu jest uproszczonym przykładem ilustrującym bieżące użycie.

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

Odpowiedz

6

Jak zauważył Pająton w poprzednim komentarzu, Popup nie jest JComponentem, do którego słuchacze mogą być łatwo związani. Ale, jak stwierdza jego dokumentacja, "implementacje Popupu są odpowiedzialne za tworzenie i utrzymywanie własnych Komponentów do renderowania [jego przedmiotu] użytkownikowi".

Używając go jako mechanizmu prezentacji, twój Popup będzie musiał zaprezentować się jako rzeczywisty komponent Swing tak czy inaczej. Czy to zarejestrować sam do tego składnika. Czy to się chowa, gdy komponent traci ostrość.

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

To jest dobre rozwiązanie. Dodanie interfejsu WindowFocusListener do wyskakującego okienka powoduje, że jest to możliwe. Skończyło się na użyciu JWindow zamiast JDialog, ponieważ nie chciałem dekoracji okna. Wezmę ostateczne rozwiązanie. –

2

Możesz dodać MouseListener do panelu tła i ukryć okienko, gdy ktoś kliknie na panelu.

Aby zareagować na minimalizację aplikacji, należy użyć WindowListener dołączonego do JFrame.

Itd. Może wydawać się nużąca, ale na pewno zadziała.

+0

Dobra sugestia. Jest to trudne w przypadku dużej aplikacji, ponieważ nie mogę dodać MouseListener do każdego komponentu na ekranie. –

+0

Szkoda, że ​​'Popup' sam nie jest' JComponentem'. Wtedy możesz dołączyć jakiegoś słuchacza, aby złapać zdarzenia, gdy straci fokus. Może rozważyć użycie 'JDialog', a następnie po prostu' MouseListener' i jego metodę 'mouseExited()'. – pajton

+0

JDialog dostarczany jest z bagażem dekoracji okiennych. Udało mi się wyśmiać coś, co używa JWindow, ale jest mnóstwo ręcznej obsługi zdarzeń i nadal kończy się to dość dziwacznym. Czy Popup naprawdę jest zepsuty, że nie może obsługiwać czegoś takiego? –

10

Użyj JPopupMenu. Możesz do niego dodać dowolny komponent, a nie tylko elementy menu.

+3

Udało mi się również zastosować to podejście. Kończy się o wiele prostsze. Wygląda na to, że zachowanie do ukrycia, gdy menu traci fokus, działa tylko wtedy, gdy przekazujesz ramkę główną jako wywoływacz w metodzie show(). Jeśli użyjesz setVisible (true), nie uzyskasz pożądanego zachowania. –

+2

Też robię to rutynowo. Po prostu ustaw układ JPopupMenu na BorderLayout i dodaj swoją treść za pomocą ograniczenia CENTER. JPopupMenu nie ma problemu z renderowaniem dowolnej zawartości huśtawki. – CarlG

+0

Próbowałem więcej postaw (bez granic JDialog, javax.swing.Popup) i wydaje się, że to najlepsze rozwiązanie. –

1

Możesz dodać FocusListener do okna wyskakującego i usunąć je, gdy straci fokus. Jednak spowoduje to pewne problemy, gdy utrata ostrości jest spowodowana inną aplikacją (nowe okna wychodzą na pierwszy plan, przełączasz wirtualne pulpity itp.).

Ale może (a) wiesz, że to nie może się zdarzyć w Twój przypadek lub (b) i tak chciałby zamknąć popup w takich przypadkach, podejście oparte na skupieniu może być dla ciebie interesujące.

2

Dzięki pajton i Noel Ang za skierowanie mnie we właściwym kierunku! Oto rozwiązanie, z którego skorzystałem. Po prostu włączam to tutaj, aby inni mogli z niego korzystać.

Skończyłem z JWindow, ponieważ nie dostał dekoracje okna, ale robi się fokus zdarzeń.

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); 
    } 
} 
Powiązane problemy