我正在为我的程序添加一个帮助菜单,我试图找出是否有办法拦截键盘输入,而不必在JFrame上使用setFocusable方法。如果我将焦点设置到框架并按F1,则没有问题。当他们按下任何其他组件时会出现问题。帧不再处于焦点位置,因此F1键不再显示菜单。我是这样做的
package helpmenu;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
public class HelpMenu extends JFrame
{
public HelpMenu()
{
setSize(300, 300);
setTitle("Help Menu");
}
/**
* Sets a KeyListener to
* the passed in JFrame.
* @param mainFrame
*/
public void callMenu( JFrame mainFrame )
{
mainFrame.addKeyListener( new functionListener() ); //Set keylistener to the main frame.
mainFrame.setFocusable(true); //Put the main frame into focus.
}
/**
* Inner KeyListener
* class for the mainFrame
* @author Shaun
*/
class functionListener implements KeyListener
{
@Override
public void keyPressed(KeyEvent e)
{
//Check if the F1 key was pressed
if ( e.getKeyCode() == KeyEvent.VK_F1 ) {
setVisible(true);
}
}
@Override
public void keyReleased(KeyEvent e) {}
@Override
public void keyTyped(KeyEvent e) {}
}
}
答案 0 :(得分:3)
不要将KeyListener用于此类事情。正如您所注意到的,一个原因是它要求组件成为焦点。而是使用WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
输入映射use a Key Binding。
另外,有些相关,请参阅"The Use of Multiple JFrames, Good/Bad Practice?"您的帮助菜单应该是JDialog。
以下是使用密钥绑定的示例:
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
应该涵盖组件本身的重点,但事实并非如此。