简体   繁体   English

为什么JDialog不触发键侦听器的keyPressed方法?

[英]Why isn't the JDialog triggering the key listener's keyPressed method?

This is my code 这是我的代码

 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());
     }
}

What I am trying to do here is when the user clicks the JButton that was added to the JToolBar with the attributes of its action, the user will be prompted with my own customized dialog box. 我要在这里做的是,当用户单击添加到具有其操作属性的JToolBar的JButton时,系统将通过我自己的自定义对话框提示用户。 The user can then press any key to close the dialog box.(it actually just be invisible). 然后,用户可以按任意键关闭对话框。(实际上它是不可见的)。 When I run the application, everything looks fine. 当我运行该应用程序时,一切看起来都很好。 The JToolBar looks right and the button looks right. JToolBar看起来正确,按钮看起来正确。 When I click the button, the correct controller behavior occurs as the dialog box is popped up.(just visible) However the key adapter's keyPressed method isn't being triggered at all when i press a key. 当我单击该按钮时,将弹出对话框,从而发生正确的控制器行为。(仅可见)但是当我按下一个键时,根本不会触发键适配器的keyPressed方法。

What I've done to debug this is to first make sure that the JDialog can first of all be focusable so it can receive key events from the keyboard. 我要做的调试工作是首先确保JDialog首先可以具有焦点,以便它可以接收来自键盘的键事件。 I did that with this line of 我是这样做的

System.out.println(myDialog.getFocusableWindowState());

and what I got on the console was true. 我在控制台上得到的是真的。 Next I made sure that the key listener was being set. 接下来,我确保已设置了关键侦听器。 I did that with 我做到了

 System.out.println( myDialog.getKeyListeners());

and this printed out 然后打印出来

[Ljava.awt.event.KeyListener;@350b914b

which I assumed was a correct memory address for an object allocated from the heap. 我假设这是从堆分配的对象的正确内存地址。

I then checked out similar threads. 然后,我签出了类似的线程。

My issue couldn't be Jbutton listener isn't triggered, why? 我的问题不能是未触发Jbutton侦听器,为什么? because the dialog box showed up and I made sure that the key listener was added with the print key listeners line. 因为出现了对话框,并且我确保在键侦听器中添加了打印键侦听器行。 I couldn't use what the user said in Trying to use key Listener because I need to listen for the key press and use that key press later in my program. 我无法使用用户在尝试使用按键侦听器中所说的内容,因为我需要侦听按键并在以后的程序中使用该按键。 And this doesn't help either Why wont this KeyEvent work? 这也无济于事, 为什么这个KeyEvent无法正常工作? because I need a general reaction to key presses to obtain which key was pressed. 因为我需要对按键的一般反应以获得按下的按键。

I know that keyPressed isn't being executed because I put a breakpoint inside the method and this print statement 我知道keyPressed不会被执行,因为我在方法和此print语句中放置了一个断点

   System.out.println(KeyEvent.getKeyText(e.getKeyCode()));  

wasn't printing anything on the console. 没有在控制台上打印任何内容。

Does anyone know how i can fix this issue? 有谁知道我该如何解决这个问题?

You are adding the KeyListener to the dialog created by the JOptionPane. 您正在将KeyListener添加到JOptionPane创建的对话框中。

However, focus is on the JButton on the dialog. 但是,重点是对话框上的JButton。 KeyEvents are only dispatched to the component with focus so your key listener code is never invoked. KeyEvent仅分派给具有焦点的组件,因此永远不会调用您的键侦听器代码。

Why are you trying to listen for any key to close the dialog? 为什么要尝试听任何键以关闭对话框? The is NOT user friendly. 这不是用户友好的。 The user does not know that is the way to close the dialog since this is not a standard UI convention. 用户不知道这是关闭对话框的方法,因为这不是标准的UI约定。 The user should click on the button to close the dialog. 用户应单击按钮以关闭对话框。

If you really do need to listen to any key pressed while the dialog is open then check out Global Event Listeners which shows how you can use an AWTEventListener to listen for any key event regardless of which component has focus. 如果确实需要侦听对话框打开时按下的任何键,请查看Global Event Listeners ,该AWTEventListener显示了如何使用AWTEventListener侦听任何键事件,而与哪个组件具有焦点无关。

Having dealt with very similar issues, I encourage people who want to add listeners to the components of their JDialog to follow the approach shown here . 处理了非常相似的问题后,我鼓励希望向其JDialog组件中添加侦听器的人员遵循此处显示的方法。 It allows for more control over the components. 它允许对组件进行更多控制。

The following example demonstrates a custom dialog that validates the user's input each time the text changes using a KeyListener . 下面的示例演示一个自定义对话框,该对话框每次在使用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);
    }
}

And this is how you create and show the dialog: 这是创建和显示对话框的方式:

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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM