Como habilitar ESC para Fechar um JPopupMenu, tratando-se de janela fecha no ESC?
-
26-09-2019 - |
Pergunta
Imagine duas situações comuns combinado:Um JDialog(ou JFrame), que fecha em VK_ESCAPE (definir como chave de ligação na raiz do painel) e um interior JPopupMenu que é suposto para fechar ESC bem.O problema é:pressionar escape sempre fecha a caixa de diálogo evento, se o pop-up é visível.Aparentemente, o pop-up não receber o evento-chave para que ele não pode ser consumido pelo pop-up.Existe alguma maneira de obter esta funcionando corretamente, de modo que no primeiro ESC-evento de pop-up está fechado e na segunda, a caixa de diálogo fecha?A propósito:Ele funciona com um JComboBox, que, por padrão, fecha-se quando a fuga é pressionado.
Solução
Encontrar uma solução genérica foi um pouco de um desafio.Precisamos considerar quando:
- um peso leve pop-up é usado
- um peso pesado, pop-up é usado
Eu determinou que, em ambos os casos, a raiz do painel, na verdade, tem o foco quando for premida a tecla escape.
No primeiro caso, eu só procurar a raiz do painel para ver se um JPopupMenu foi adicionado à interface gráfica.Se é assim, então podemos simplesmente fechar a pop-up.
No segundo caso, a Janela é criada para conter o JPopupMenu para eu fazer uma pesquisa para ver se um visível personalizado Janela pop-up é exibida.Se é assim, então posso descartar a janela.
Se nenhum dos anteriores dois casos é verdade, você pode simplesmente fechar a caixa de diálogo.
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 );
}
}
Também será necessário baixar o Balanço Utils de classe.