【问题标题】:Why isn't the JDialog triggering the key listener's keyPressed method?为什么 JDialog 不触发按键侦听器的 keyPressed 方法?
【发布时间】:2015-01-26 07:56:08
【问题描述】:

这是我的代码

 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 listener isn't triggered, why?,因为出现了对话框,并且我确保键侦听器已与打印键侦听器行一起添加。 我无法使用用户在Trying to use key Listener 中所说的内容,因为我需要监听按键并稍后在我的程序中使用该按键。 这也无济于事Why wont this KeyEvent work? 因为我需要对按键做出一般反应才能确定按下了哪个键。

我知道 keyPressed 没有被执行,因为我在方法和这个 print 语句中放置了一个断点

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

没有在控制台上打印任何内容。

有谁知道我该如何解决这个问题?

【问题讨论】:

    标签: java swing keylistener jdialog


    【解决方案1】:

    您正在将 KeyListener 添加到由 JOptionPane 创建的对话框中。

    但是,焦点是对话框上的 JButton。 KeyEvents 仅被分派到具有焦点的组件,因此您的键侦听器代码永远不会被调用。

    您为什么要尝试侦听关闭对话框的任何键?这不是用户友好的。用户不知道这是关闭对话框的方式,因为这不是标准的 UI 约定。用户应单击按钮关闭对话框。

    如果您确实需要在对话框打开时监听任何按下的键,请查看Global Event Listeners,它展示了如何使用AWTEventListener 监听任何键事件,而不管哪个组件具有焦点。

    【讨论】:

    • 我的意思是我可以将它包含在对话消息中
    • @committedandroider,微软和苹果等公司花费数百万美元开发任何用户都可以使用的一致界面。为什么你认为你需要开发自己的自定义界面。通过单击按钮或使用退出键来关闭对话框。您无需按任何键即可关闭对话框。
    • 是的,谢谢。我牢记这一点。但就这个项目而言,我改变了 myDialog.addKeyListener(new KeyGetter());只需 addKeyListener(new KeyGetter()); myDialog.removeKeyListener(getKeyListeners()[0]);并删除KeyListener(getKeyListeners()[0]);这样键侦听器将被附加到 Jbutton 上。但是对话框仍然不会关闭....
    • 这可能是个愚蠢的问题,但 Swing 是否真的用于微软和苹果等公司?
    【解决方案2】:

    在处理了非常相似的问题之后,我鼓励想要在 JDialog 的组件中添加侦听器的人遵循here 所示的方法。它允许对组件进行更多控制。

    以下示例演示了一个自定义对话框,该对话框使用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);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-26
      • 1970-01-01
      • 2011-07-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-18
      • 1970-01-01
      相关资源
      最近更新 更多