java 单击其他位置时如何隐藏 Swing 弹出窗口

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2581314/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 21:54:01  来源:igfitidea点击:

How do you hide a Swing Popup when you click somewhere else

javaswingpopup

提问by Casey Watson

I have a Popup that is shown when a user clicks on a button. I would like to hide the popup when any of the following events occur:

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

  1. The user clicks somewhere else in the application. (The background panel for example)
  2. The user minimizes the application.
  1. 用户单击应用程序中的其他位置。(以背景面板为例)
  2. 用户最小化应用程序。

The JPopupMenu has this behavior, but I need more than just JMenuItems. The following code block is a simplified illustration to demonstrate the current usage.

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

采纳答案by Noel Ang

As pajton noted in a previous comment, Popup is not a JComponent to which listeners can be readily bound. But, as its documentation states, "implementations of Popup are responsible for creating and maintaining their own Components to render [its subject] to the user."

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

So in using it as your presentation mechanism, your Popup is going to have to present itself as an actual Swing component anyway. Have it register itselfto that component. Have it hide itself when the component loses focus.

因此,在使用它作为您的展示机制时,您的 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);
    }
}

回答by camickr

Use a JPopupMenu. You can add any component to it, not just menu items.

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

回答by Casey Watson

Thanks pajton and Noel Ang for getting me pointed in the right direction! Here is the solution that I ended up with. I'm just including it here so that others may benefit from it.

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

I ended up going with a JWindow since it doesn't get the window decorations but does get focus events.

我最终选择了 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);
  }
}

回答by pajton

You can add MouseListenerto your background panel and hide the popup when somebody clicks on the panel.

您可以将MouseListener添加到您的背景面板并在有人单击面板时隐藏弹出窗口。

To react on application minimization, use WindowListenerattached to a JFrame.

要对应用程序最小化做出反应,请使用附加到JFrame 的WindowListener

Etc, etc. May seem tedious, but surely will work.

等等等等。可能看起来很乏味,但肯定会奏效。

回答by Thomas

You could add a FocusListener to your popup-window, and dispose it when it loses focus. However, that will cause you some troubles when the focus loss is due to some other application (new windows comes to the foreground, you switch virtual desktops, etc.)

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

But perhaps you (a) know that that cannot happen in your case or (b) would want to close the popup in such cases anyway, a focus-based approach may still be interesting to you.

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

回答by Hulk

I know this is an old question but I really needed the Popup to work in my case. So I tried a few things and the following is my solution.

我知道这是一个老问题,但我真的需要 Popup 在我的情况下工作。所以我尝试了一些事情,以下是我的解决方案。

Add a FocusListenerto the component you add to the popup and program the focusLostevent on that component to hide the popup when focus is lost. Call the requestFocusmethod on your component just after showing the popup.

将 aFocusListener添加到您添加到弹出窗口的组件中,并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);
    }
}