我有一个用户点击按钮时显示的Popup。我想在发生以下任何事件时隐藏弹出窗口:
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);
}
}
答案 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添加到后台面板,并在有人点击面板时隐藏弹出窗口。
要对应用最小化做出反应,请使用附加到WindowListener的JFrame。
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);
}
}