当你点击其他地方时,如何隐藏Swing Popup

时间:2010-04-05 21:34:18

标签: java swing popup

我有一个用户点击按钮时显示的Popup。我想在发生以下任何事件时隐藏弹出窗口:

  1. 用户点击应用程序中的其他位置。 (例如背景面板)
  2. 用户最小化应用程序。
  3. JPopupMenu有这种行为,但我需要的不仅仅是JMenuItems。以下代码块是演示当前用法的简化图示。

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

6 个答案:

答案 0 :(得分:11)

使用JPopupMenu。您可以向其添加任何组件,而不仅仅是菜单项。

答案 1 :(得分:6)

正如pajton在之前的评论中指出的那样,Popup不是一个可以轻松绑定侦听器的JComponent。但是,正如其文档所述,“Popup的实现负责创建和维护自己的组件以向用户呈现[其主题]。”

因此,在使用它作为您的表示机制时,您的Popup将不得不将自己呈现为实际的Swing组件 。让它将本身注册到该组件。当组件失去焦点时,让它自己隐藏。

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

答案 2 :(得分:2)

您可以将MouseListener添加到后台面板,并在有人点击面板时隐藏弹出窗口。

要对应用最小化做出反应,请使用附加到WindowListenerJFrame

Etc等似乎很乏味,但肯定会奏效。

答案 3 :(得分:2)

感谢pajton和Noel Ang让我指出了正确的方向!这是我最终的解决方案。我只是把它包括在这里,以便其他人可以从中受益。

我最终选择了一个JWindow,因为它没有获得窗口装饰,但确实得到了焦点事件。

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

答案 4 :(得分:1)

您可以将FocusListener添加到弹出窗口,并在失去焦点时将其丢弃。但是,当焦点丢失是由于某些其他应用程序(新窗口出现在前台,您切换虚拟桌面等)时,这会导致一些麻烦。

但也许你(a)知道在你的情况下不会发生这种情况或者(b)想要在这种情况下关闭弹出窗口,基于焦点的方法可能仍然对你感兴趣。

答案 5 :(得分:0)

我知道这是一个老问题,但我确实需要Popup才能正常工作。因此,我尝试了一些方法,以下是我的解决方案。

向添加到弹出窗口的组件添加FocusListener,并对该组件上的focusLost事件进行编程,以在焦点丢失时隐藏弹出窗口。显示弹出窗口后,立即在组件上调用requestFocus方法。

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;

import javax.swing.*;

public class PopupTester extends JFrame {
    JButton myButton = new JButton("Click Me");
    JLabel myComponent = new JLabel("Howdy");
    Popup popup = null;

    public PopupTester() {
        setLayout(new FlowLayout());
        setSize(300, 100);
        add(myButton);
        add(new JButton("No Click Me"));
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        myComponent.addFocusListener(new FocusAdapter() {
            public void focusLost(FocusEvent e) {
                if (popup != null) {
                    popup.hide();
                }
            }
        });

        myButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                if (popup != null) {
                    popup.hide();
                    popup = null;
                }

                Point location = myButton.getLocationOnScreen();
                int y = (int) (location.getY() + myButton.getHeight());
                int x = (int) location.getX();
                popup = PopupFactory.getSharedInstance().getPopup(PopupTester.this, myComponent, x, y);
                popup.show();
                myComponent.requestFocus();
            }
        });
    }

    public static void main(String[] args) {
        PopupTester popupTester = new PopupTester();
        popupTester.setVisible(true);
    }
}