这是我的代码
JToolBar customizeKeys = new JToolBar();
customizeKeys.add(new ChangeKeyListen("left"));
private class ChangeKeyListen extends AbstractAction{
private JDialog myDialog;
class KeyGetter extends KeyAdapter {
@Override
public void keyPressed(KeyEvent e) {
super.keyPressed(e);
OtherPanel.this.map(
KeyEvent.getKeyText(e.getKeyCode()),
keyAction);
myDialog.setVisible(false);
myDialog.removeKeyListener(getKeyListeners()[0]);
}
};
public ChangeKeyListen(String name) {
super(name);
}
@Override
public void actionPerformed(ActionEvent e) {
myDialog = new JOptionPane().createDialog("Press a key");
myDialog.setVisible(true);
myDialog.requestFocusInWindow();
System.out.println(myDialog.getFocusableWindowState());
myDialog.addKeyListener(new KeyGetter());
System.out.println( myDialog.getKeyListeners());
}
}
我在这里尝试做的是,当用户单击添加到 JToolBar 及其操作属性的 JButton 时,将提示用户我自己定制的对话框。然后用户可以按任意键关闭对话框。(它实际上只是不可见)。当我运行该应用程序时,一切看起来都很好。 JToolBar 看起来正确,按钮看起来也正确。当我单击按钮时,弹出对话框时会出现正确的控制器行为。(仅可见)但是当我按下某个键时,根本不会触发按键适配器的 keyPressed 方法。
我对此所做的调试是首先确保 JDialog 可以聚焦,以便它可以从键盘接收按键事件。我用这行
做到了System.out.println(myDialog.getFocusableWindowState());
我在控制台上得到的信息是真的。接下来,我确保已设置关键侦听器。我用
做到了 System.out.println( myDialog.getKeyListeners());
并且打印出来了
[Ljava.awt.event.KeyListener;@350b914b
我认为这是从堆分配的对象的正确内存地址。
然后我查看了类似的线程。
我的问题不可能是 Jbutton 侦听器未触发,为什么? 因为出现了对话框,并且我确保使用 print key Listeners 行添加了关键侦听器。 我无法使用用户在尝试使用按键监听器中所说的内容,因为我需要监听按键并稍后在程序中使用该按键。 这也没有帮助为什么这个 KeyEvent 不起作用? 因为我需要对按键的一般反应来获取按下了哪个键。
我知道 keyPressed 没有被执行,因为我在方法和这个打印语句中放置了一个断点
System.out.println(KeyEvent.getKeyText(e.getKeyCode()));
没有在控制台上打印任何内容。
有人知道如何解决这个问题吗?
您正在将 KeyListener 添加到 JOptionPane 创建的对话框中。
但是,焦点位于对话框上的 JButton 上。 KeyEvent 仅分派到具有焦点的组件,因此永远不会调用您的关键侦听器代码。
为什么要尝试监听任意键来关闭对话框?这对用户来说并不友好。用户不知道这是关闭对话框的方法,因为这不是标准的 UI 约定。用户应该单击按钮来关闭对话框。
如果您确实需要在对话框打开时监听按下的任何按键,请查看 Global Event Listeners,其中展示了如何使用
AWTEventListener
监听任何按键事件,无论哪个组件具有焦点。
处理过非常类似的问题后,我鼓励想要向 JDialog 组件添加侦听器的人遵循此处所示的方法。它允许对组件进行更多控制。
以下示例演示了一个自定义对话框,每次文本更改时使用 KeyListener 验证用户的输入。
public class DialogWithListener extends JDialog {
private JTextField textField = new JTextField();
private boolean userPressedOk = false;
/**
* Creates a dialog that lets the user enter text in a text field.
* <p>
* Each time the user presses a key, the text is validated using the
* {@link Predicate}s in {@code predsAndMsgs}. If the text doesn't satisfy
* all predicates, the dialog shows the message associated with the first
* unsatisfied predicate.
*
* @param predsAndMsgs
* a map from {@link Predicate}s to the messages we'll show to
* users if the text they entered doesn't satisfy the predicates
*/
public DialogWithListener(Map<Predicate<String>, String> predsAndMsgs) {
JLabel textFieldLabel = new JLabel("Enter text:");
// Show this if the text the user entered satisfies our predicates
String okText = "All good";
JLabel statusLabel = new JLabel(okText);
Object[] paneContent = { textFieldLabel, textField, statusLabel };
JButton okButton = new JButton("OK");
okButton.addActionListener(e -> {
userPressedOk = true;
setVisible(false);
});
Object[] options = { okButton };
JOptionPane optionPane = new JOptionPane(paneContent,
JOptionPane.QUESTION_MESSAGE, JOptionPane.DEFAULT_OPTION, null,
options);
getContentPane().add(optionPane);
setLocationRelativeTo(optionPane.getParent());
setFocusTo(textField);
// Check the user input each time a key is released
textField.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent event) {
validate(predsAndMsgs, textField.getText(), okText,
statusLabel, okButton);
}
});
setModal(true);
setResizable(false);
pack();
}
/**
* Validates the {@code textToValidate}.
* <p>
* The {@link Predicate}s in {@link predsAndMsgs} determine whether the text
* is valid. If the text is invalid, we show the message that is associated
* with the predicate and disable this dialog's OK button.
*
* @param predsAndMsgs
* a map from {@link Predicate}s that must hold for the
* {@code textToValidate} to the messages we'll show to the user
* if a predicate is not satisfied.
* @param textToValidate
* we validate this text against the {@link Predicate}s in
* {@link predsAndMsgs}
* @param okText
* this text is shown if the {@code textToValidate} satisfies all
* predicates
* @param statusLabel
* a {@link JLabel} that either shows the {@link okText} or the
* message of the first predicate that doesn't hold true for the
* {@link textToValidate}
* @param okButton
* we enable and disable this button depending on whether the
* {@link textToValidate} is valid
*/
private void validate(Map<Predicate<String>, String> predsAndMsgs,
String textToValidate, String okText, JLabel statusLabel,
JButton okButton) {
// Get the first predicate that the text to validate doesn't satisfy
Optional<Predicate<String>> unsatisfiedPredMaybe = predsAndMsgs
.keySet().stream().filter(pred -> !pred.test(textToValidate))
.findFirst();
// At least one predicate was not satisfied
if (unsatisfiedPredMaybe.isPresent()) {
// Tell the user the text they entered can't be accepted
String msg = predsAndMsgs.get(unsatisfiedPredMaybe.get());
statusLabel.setText(msg);
okButton.setEnabled(false);
} else {
statusLabel.setText(okText);
okButton.setEnabled(true);
}
pack();
}
private void setFocusTo(JComponent comp) {
addComponentListener(new ComponentAdapter() {
@Override
public void componentShown(ComponentEvent ce) {
comp.requestFocusInWindow();
}
});
}
public Optional<String> display() {
userPressedOk = false;
// Because the dialog is modal it will block here
setVisible(true);
String dialogResult = null;
if (userPressedOk) {
dialogResult = textField.getText();
}
return Optional.ofNullable(dialogResult);
}
}
这就是创建和显示对话框的方式:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager
.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException
| UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
JFrame frame = new JFrame();
JButton showDialogButton = new JButton("Show Dialog");
// Define the predicates that the user-entered text should satisfy and
// the messages shown to the user if it doesn't
Map<Predicate<String>, String> predicatesAndMessages = new HashMap<>();
Predicate<String> dontMentionHisName = text -> !text
.contains("Voldemort");
predicatesAndMessages.put(dontMentionHisName,
"Sssh! You can't say that!");
DialogWithListener dialog = new DialogWithListener(
predicatesAndMessages);
dialog.setTitle("My dialog");
showDialogButton.addActionListener(e -> dialog.display().ifPresent(
userText -> System.out.println(userText)));
frame.getContentPane().add(showDialogButton);
frame.pack();
frame.setVisible(true);
}