想象一下两种常见情况的组合:在 VK_ESCAPE 上关闭的 JDialog(或 JFrame)(设置为根窗格上的键绑定)和应该在 ESC 上关闭的内部 JPopupMenu。问题是:如果弹出窗口可见,按转义总是关闭对话框 - 事件。显然弹出窗口甚至没有收到关键事件,因此它不能被弹出窗口使用。有没有办法让它正常工作,以便在第一个 ESC 事件时弹出窗口关闭,而在第二个对话框关闭?顺便说一句:它确实可以与 JComboBox 一起使用,默认情况下,当按下转义键时它会关闭。
问问题
1936 次
2 回答
5
找到一个通用的解决方案有点挑战。我们需要考虑什么时候:
- 使用轻量级弹出窗口
- 使用了重量级的弹出窗口
我确定在这两种情况下,当按下转义键时,根窗格实际上具有焦点。
在第一种情况下,我只搜索根窗格以查看是否已将 JPopupMenu 添加到 GUI。如果是这样,那么我们可以关闭弹出窗口。
在第二种情况下,创建了一个包含 JPopupMenu 的窗口,因此我进行搜索以查看是否显示了可见的自定义弹出窗口。如果是这样,那么我处理窗口。
如果以上两种情况都不成立,那么您可以关闭对话框。
import java.awt.*;
import java.awt.event.*;
import java.util.List;
import javax.swing.*;
import javax.swing.event.*;
public class DialogEscape extends JDialog
{
private JPopupMenu popup;
public DialogEscape()
{
popup = new JPopupMenu();
popup.add( new JMenuItem("SubMenuA") );
popup.add( new JMenuItem("SubMenuB") );
popup.add( new JMenuItem("SubMenuC") );
popup.add( new JMenuItem("SubMenuD") );
String[] items = { "Select Item", "Color", "Shape", "Fruit" };
JComboBox comboBox = new JComboBox( items );
add(comboBox, BorderLayout.NORTH);
JTextField textField = new JTextField("Right Click For Popup");
textField.setComponentPopupMenu(popup);
add(textField);
KeyStroke escapeKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
Action escapeAction = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
boolean openPopup = false;
Component c = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
// Check if light weight popup is being used
List<JPopupMenu> popups = SwingUtils.getDescendantsOfType(JPopupMenu.class, (Container)c, true);
for (JPopupMenu p: popups)
{
p.setVisible( false );
openPopup = true;
}
// Check if a heavy weight popup is being used
Window window = SwingUtilities.windowForComponent(c);
Window[] windows = window.getOwnedWindows();
for (Window w: windows)
{
if (w.isVisible()
&& w.getClass().getName().endsWith("HeavyWeightWindow"))
{
openPopup = true;
w.dispose();
}
}
// No popups so close the Window
if (! openPopup)
// SwingUtilities.windowForComponent(c).setVisible(false);
SwingUtilities.windowForComponent(c).dispose();
}
};
getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(escapeKeyStroke, "ESCAPE");
getRootPane().getActionMap().put("ESCAPE", escapeAction);
}
public static void main(String[] args)
{
String laf = null;
laf = "javax.swing.plaf.metal.MetalLookAndFeel";
// laf = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
// laf = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
try { UIManager.setLookAndFeel(laf); }
catch (Exception e2) { System.out.println(e2); }
JDialog dialog = new DialogEscape();
dialog.setDefaultCloseOperation( HIDE_ON_CLOSE );
dialog.setSize(200, 200);
dialog.setLocationRelativeTo(null);
dialog.setVisible( true );
}
}
您还需要下载Swing Utils类。
于 2010-09-29T04:33:42.033 回答
0
我也遇到了这个问题。@camickr 提供的解决方案对我来说似乎不是很好。所以我检查了引擎盖下发生了什么。打开弹出窗口时,作为弹出窗口调用者的组件失去焦点。焦点转到 JDialog 的 JRootPane,然后委托给弹出窗口。因此,我没有在 JRootPane 上注册“ESC”快捷方式,而是将其放在 ContentPane 上。这样,只有在聚焦 JRootPane 以外的任何内容时,对话框才会在 ESC 上关闭。
final JComponent contentPane = (JComponent) dialog.getContentPane();
contentPane.getInputMap( JComponent.WHEN_IN_FOCUSED_WINDOW ).put( KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, 0 ), "EXIT" );
contentPane.getActionMap().put( "EXIT", new AbstractAction()
{
@Override
public void actionPerformed( final ActionEvent e )
{
dialog.dispatchEvent( new WindowEvent( dialog, WindowEvent.WINDOW_CLOSING ) );
}
} );
于 2020-06-08T09:57:01.530 回答