Как вы скрываете всплывающее окно Swing, когда вы нажимаете в другом месте
У меня есть всплывающее окно, которое отображается, когда пользователь нажимает кнопку. Я хотел бы скрыть всплывающее окно, когда произойдет одно из следующих событий:
- Пользователь щелкает в другом месте приложения. (Например, фоновая панель)
- Пользователь минимизирует приложение.
У 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);
}
}
Ответы
Ответ 1
Как отметил в предыдущем комментарии pajton, Popup не является JComponent, к которому слушатели могут быть легко связаны. Но, как утверждает его документация, "реализации 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
Используйте JPopupMenu. Вы можете добавить к нему любой компонент, а не только элементы меню.
Ответ 3
Вы можете добавить MouseListener на свою фоновую панель и скрыть всплывающее окно, когда кто-то нажимает на панель.
Чтобы реагировать на минимизацию приложения, используйте WindowListener, прикрепленный к JFrame.
Etc и т.д. Может показаться утомительным, но, безусловно, сработает.
Ответ 4
Спасибо 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);
}
}
Ответ 5
Вы можете добавить FocusListener в свое всплывающее окно и утилизировать его, когда он теряет фокус. Тем не менее, это вызовет некоторые проблемы, когда потеря фокуса связана с каким-либо другим приложением (на передний план выходят новые окна, вы переключаете виртуальные рабочие столы и т.д.).
Но, возможно, вы (а) знаете, что этого не может быть в вашем случае, или (б) захочет закрыть всплывающее окно в таких случаях, в любом случае фокус-ориентированный подход может быть вам интересен.