Не используйте KeyListener для этого типа вещей. Как вы заметили, одной из причин является то, что компонент должен быть в фокусе. Вместо этого use a Key Binding с входной картой WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
.
Кроме того, некоторые из связанных, см. "The Use of Multiple JFrames, Good/Bad Practice?" Возможно, ваше меню справки должно быть JDialog.
Вот пример использования ключа Binding:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class HelpDialogEx {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new HelpDialogEx();
}
});
}
final JFrame frame = new JFrame("Press F1 for help");
final JPanel cpane = new JPanel(new GridLayout(4, 5, 10, 10));
final HelpDialog help = new HelpDialog(frame);
final AbstractAction helpToggle = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
help.setVisible(!help.isVisible());
}
};
HelpDialogEx() {
for(int i = 0; i < 20; i++) {
cpane.add(new JButton("Nil"));
}
cpane.setPreferredSize(new Dimension(640, 480));
frame.setContentPane(cpane);
addHelpToggle(frame.getRootPane());
addHelpToggle(help.getRootPane());
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
void addHelpToggle(JComponent comp) {
KeyStroke f1Key = KeyStroke.getKeyStroke(
KeyEvent.VK_F1, 0, true
);
String cmd = "helpToggle";
for(InputMap im : new InputMap[] {
comp.getInputMap(JComponent.WHEN_FOCUSED),
comp.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
}) {
im.put(f1Key, cmd);
}
comp.getActionMap().put(cmd, helpToggle);
}
static class HelpDialog
extends JDialog {
HelpDialog(Window parent) {
super(parent, "\"Help\"", Dialog.ModalityType.MODELESS);
JTextArea doc = new JTextArea(getUnhelpfulText());
doc.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
doc.setEditable(false);
doc.setLineWrap(true);
JScrollPane scroll = new JScrollPane(doc);
scroll.getViewport().setPreferredSize(new Dimension(480, 360));
setContentPane(scroll);
pack();
setLocationRelativeTo(null);
}
static String getUnhelpfulText() {
StringBuilder sb = new StringBuilder();
addRandomParagraph(sb);
for(int i = 0; i < 3; i++) {
sb.append("\n\n");
addRandomParagraph(sb);
}
return sb.toString();
}
static void addRandomParagraph(StringBuilder sb) {
sb.append(" ");
addRandomSentence(sb);
for(int i = 0; i < 10; i++) {
sb.append(' ');
addRandomSentence(sb);
}
}
static void addRandomSentence(StringBuilder sb) {
sb.append((char)(Math.random() * 26 + 'A'));
for(int i = (int)(Math.random() * 10 + 1); i > 0; i--) {
for(int len = (int)(Math.random() * 10 + 1); len > 0; len--) {
sb.append((char)(Math.random() * 26 + 'a'));
}
sb.append(' ');
}
sb.setCharAt(sb.length() - 1, '.');
}
}
}
Я обнаружил, что, хотя в учебнике говорится, что WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
должен охватывать, когда сам компонент ориентирован, это не так.
Почему бы просто не использовать обычные программы JMenu? Вы можете добавить мнемонику и ускорители в меню с помощью 'Action'. См. [Пример] (http://stackoverflow.com/a/21583281/2587435) –
@peeskillet Это отличное предложение. – Radiodef