Java Swing持久弹出窗口
我需要显示一个带有自定义组件的swing弹出窗口。弹出窗口应该保持可见,直到我自己隐藏它,但不应该获得焦点 我有一个由其他开发人员编写的代码,它以以下方式执行:Java Swing持久弹出窗口,java,swing,mouseevent,jpopupmenu,jpopup,Java,Swing,Mouseevent,Jpopupmenu,Jpopup,我需要显示一个带有自定义组件的swing弹出窗口。弹出窗口应该保持可见,直到我自己隐藏它,但不应该获得焦点 我有一个由其他开发人员编写的代码,它以以下方式执行: popupMenu = new JPopupMenu(); popupMenu.add(myCustomComponent, BorderLayout.CENTER); popupMenu.setFocusable(false); popupMenu.setVisible(true
popupMenu = new JPopupMenu();
popupMenu.add(myCustomComponent, BorderLayout.CENTER);
popupMenu.setFocusable(false);
popupMenu.setVisible(true);
popupMenu.show(parentComponent, x, y);
这似乎是可行的,但有一个错误-当弹出窗口可见时,组件外的第一次鼠标单击将被弹出窗口使用。因此,我需要单击两次以将焦点设置为另一个组件
我怎样才能修好它?或者,弹出窗口的正确方式是什么
更新
最后,我设法用简短的代码片段重现了我的问题。感谢纪尧姆·波尔特给了我一个起点
代码如下:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
public class TestJPopup {
protected void initUI() {
JFrame frame = new JFrame(TestJPopup.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JTextField textField = new JTextField("Some text field");
frame.add(textField, BorderLayout.WEST);
final JButton buttonToHit = new JButton("Hit me");
buttonToHit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(buttonToHit, "You hit the button successfully");
}
});
frame.add(buttonToHit);
frame.setSize(200, 100);
frame.setVisible(true);
final JPopupMenu popup = new JPopupMenu();
popup.add(new JLabel("<html>Hey!<br>I'm the popup window!</html>"),
BorderLayout.NORTH);
popup.setFocusable(false);
popup.setVisible(true);
popup.show(textField, 60, 60);
// I want to activate popup when user clicks in the text field
textField.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (popup != null) {
popup.show(textField, 60, 60);
}
}
});
}
public static void main(String[] args) throws Exception {
Class lnfClass = Class.forName("com.sun.java.swing.plaf.windows.WindowsLookAndFeel", true,
Thread.currentThread().getContextClassLoader());
LookAndFeel feel = (LookAndFeel) lnfClass.newInstance();
UIManager.setLookAndFeel(feel);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TestJPopup().initUI();
}
});
}
}
导入java.awt.BorderLayout;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.awt.event.MouseAdapter;
导入java.awt.event.MouseEvent;
导入javax.swing.*;
公共类TestJPopup{
受保护的void initUI(){
JFrame=newjframe(TestJPopup.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
最终JTextField textField=新的JTextField(“某些文本字段”);
frame.add(textField,BorderLayout.WEST);
最终JButton buttonothit=新JButton(“击中我”);
addActionListener(新建ActionListener()){
已执行的公共无效操作(操作事件e){
showMessageDialog(buttonToHit,“您成功地点击了按钮”);
}
});
frame.add(buttonothit);
框架设置尺寸(200100);
frame.setVisible(true);
最终JPopupMenu弹出窗口=新建JPopupMenu();
添加(新的JLabel(“嘿!
我是弹出窗口!”),
边界布局(北面);
popup.setFocusable(false);
popup.setVisible(true);
显示(文本字段,60,60);
//我想在用户单击文本字段时激活弹出窗口
addMouseListener(新的MouseAdapter(){
@凌驾
公共无效mouseClicked(MouseEvent e){
如果(弹出!=null){
显示(文本字段,60,60);
}
}
});
}
公共静态void main(字符串[]args)引发异常{
Class lnfClass=Class.forName(“com.sun.java.swing.plaf.windows.WindowsLookAndFeel”,true,
Thread.currentThread().getContextClassLoader());
LookAndFeel=(LookAndFeel)lnfClass.newInstance();
UIManager.setLookAndFeel(feel);
SwingUtilities.invokeLater(新的Runnable(){
公开募捐{
新的TestJPopup().initUI();
}
});
}
}
两个关键时刻:
- 使用的Windows外观(默认不可复制)
- 鼠标侦听器连接到主框架中的文本字段
- 这不是答案,只是一个我目前无法重现您描述的行为的例子。也许从这段代码开始,试着用修改过的非工作代码重现错误和编辑文章
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class TestJPopup {
protected void initUI() {
JFrame frame = new JFrame(TestJPopup.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel leftLabel = new JLabel("Left");
frame.add(leftLabel, BorderLayout.WEST);
final JButton buttonToHit = new JButton("Hit me");
buttonToHit.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(buttonToHit, "You hit the button successfully");
}
});
frame.add(buttonToHit);
frame.setSize(500, 400);
frame.setVisible(true);
JPopupMenu popupMenu = new JPopupMenu();
popupMenu.add(new JLabel("<html>A Custom<br>component<br>made to<br> simulate <br>your custom component</html>"),
BorderLayout.NORTH);
JTextField textfield = new JTextField(30);
popupMenu.add(textfield);
popupMenu.setFocusable(false);
popupMenu.setVisible(true);
popupMenu.show(leftLabel, 20, 20);
// Let's force the focus to be in a component in the popupMenu
textfield.requestFocusInWindow();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new TestJPopup().initUI();
}
});
}
}
导入java.awt.BorderLayout;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入javax.swing.JButton;
导入javax.swing.JFrame;
导入javax.swing.JLabel;
导入javax.swing.JOptionPane;
导入javax.swing.jpopmenu;
导入javax.swing.JTextField;
导入javax.swing.SwingUtilities;
公共类TestJPopup{
受保护的void initUI(){
JFrame=newjframe(TestJPopup.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel leftLabel=新的JLabel(“左”);
frame.add(leftLabel,BorderLayout.WEST);
最终JButton buttonothit=新JButton(“击中我”);
addActionListener(新建ActionListener()){
@凌驾
已执行的公共无效操作(操作事件e){
showMessageDialog(buttonToHit,“您成功地点击了按钮”);
}
});
frame.add(buttonothit);
框架。设置尺寸(500400);
frame.setVisible(true);
JPopupMenu=新的JPopupMenu();
popupMenu.add(新的JLabel(“为模拟您的自定义组件而制作的自定义组件”),
边界布局(北面);
JTextField textfield=新的JTextField(30);
弹出菜单。添加(文本字段);
popupMenu.setFocusable(假);
popupMenu.setVisible(真);
显示(leftLabel,20,20);
//让我们强制焦点位于弹出菜单中的组件中
textfield.requestFocusInWindow();
}
公共静态void main(字符串[]args){
SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开募捐{
新的TestJPopup().initUI();
}
});
}
}
不是解决方案,而是:
在我看来,这就像一个bug,即使是一个普通的组件弹出窗口也会表现出相同的错误行为(在winLAF和Nimbus中,而不是在金属中):
用于快速研究和/或未来读者
- 本期可复制,并提交给 (a) (b)
- 在
和jdk1.6.0_25
上测试jdk1.7.0_04
- 关于
和WinXp
的相同问题Win7
- 对于
至Look and Feel
/systemlook and Feel
windowslook and Feel
JWindow
而不是mKorbel在评论中提出的jpopmenu
:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TestJPopup {
protected void initUI() {
final JFrame frame = new JFrame(TestJPopup.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JTextField textField = new JTextField("Some text field");
frame.add(textField, BorderLayout.WEST);
final JButton buttonToHit = new JButton("Hit me");
buttonToHit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(buttonToHit, "You hit the button successfully");
}
});
frame.add(buttonToHit);
frame.setSize(200, 70);
frame.setVisible(true);
final JWindow popup = new JWindow();
popup.getContentPane().add(new JLabel("<html>Hey!<br>I'm the popup window!</html>"),
BorderLayout.NORTH);
popup.setLocation(frame.getLocation().x + 60, frame.getLocation().y + 60);
popup.pack();
popup.setFocusable(false);
popup.setVisible(true);
// I want to activate popup when user clicks in the text field
textField.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
if (popup != null) {
popup.setVisible(true);
popup.setLocation(frame.getLocation().x + 60, frame.getLocation().y + 60);
popup.toFront();
}
}
});
textField.addFocusListener(new FocusAdapter() {
@Override
public void focusLost(FocusEvent e) {
if (popup != null) {
popup.setVisible(false);
}
}
});
}
public static void main(String[] args) throws Exception {
Class lnfClass = Class.forName("com.sun.java.swing.plaf.windows.WindowsLookAndFeel", true,
Thread.currentThread().getContextClassLoader());
LookAndFeel feel = (LookAndFeel) lnfClass.newInstance();
UIManager.setLookAndFeel(feel);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TestJPopup().initUI();
}
});
}
}
import java.awt.*;
导入java.awt.event.*;
导入javax.swing.*;
公共类TestJPopup{
受保护的void initUI(){
final JFrame=newjframe(TestJPopup.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
最终JTextField textField=新的JTextField(“某些文本字段”);
frame.add(textField,BorderLayout.WEST);
最终按钮按钮
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TestJPopup {
protected void initUI() {
final JFrame frame = new JFrame(TestJPopup.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JTextField textField = new JTextField("Some text field");
frame.add(textField, BorderLayout.WEST);
final JButton buttonToHit = new JButton("Hit me");
buttonToHit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(buttonToHit, "You hit the button successfully");
}
});
frame.add(buttonToHit);
frame.setSize(200, 70);
frame.setVisible(true);
final JWindow popup = new JWindow();
popup.getContentPane().add(new JLabel("<html>Hey!<br>I'm the popup window!</html>"),
BorderLayout.NORTH);
popup.setLocation(frame.getLocation().x + 60, frame.getLocation().y + 60);
popup.pack();
popup.setFocusable(false);
popup.setVisible(true);
// I want to activate popup when user clicks in the text field
textField.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
if (popup != null) {
popup.setVisible(true);
popup.setLocation(frame.getLocation().x + 60, frame.getLocation().y + 60);
popup.toFront();
}
}
});
textField.addFocusListener(new FocusAdapter() {
@Override
public void focusLost(FocusEvent e) {
if (popup != null) {
popup.setVisible(false);
}
}
});
}
public static void main(String[] args) throws Exception {
Class lnfClass = Class.forName("com.sun.java.swing.plaf.windows.WindowsLookAndFeel", true,
Thread.currentThread().getContextClassLoader());
LookAndFeel feel = (LookAndFeel) lnfClass.newInstance();
UIManager.setLookAndFeel(feel);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TestJPopup().initUI();
}
});
}
}
UIManager.put("PopupMenu.consumeEventOnClose", Boolean.FALSE);
// Ask UIManager about should we consume event that closes
// popup. This made to match native apps behaviour.