按键事件处理 - 按键未显示在 JLabel 上

Key event handling - key pressed doesn't show up on JLabel

提问人:stupidmoron 提问时间:5/16/2022 更新时间:5/16/2022 访问量:136

问:

我正在一本书中做一个练习,你必须测试事件处理,其中之一是关键事件。我按照书中关于如何处理 keyPressed 事件的说明进行操作,但我的密钥事件处理程序没有像它应该的那样显示 JLabel 上按下的键。这是我的代码:

import java.awt.FlowLayout;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.ItemListener;
import java.awt.event.ItemEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.InputEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.ListSelectionModel;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JCheckBox;
import javax.swing.JButton;
import javax.swing.JPanel;

public class Events extends JFrame {
    private JLabel insLabel;
    private JLabel fontLabel;
    private JLabel mouseLabel;
    private JLabel resultLabel;
    private JList fontList;
    private static final String[] fontNames = {"Serif", "SansSerif", "Monospaced"};
    private JCheckBox boldCb;
    private JCheckBox italicCb;
    private JButton submitButton;
    private JPanel middlePanel;
    private JPanel bottomPanel;
    private String fontName;
    private String fontStyle;
    
    public Events() {
        super("Demonstrating Events");
        setLayout(new BorderLayout());
        insLabel = new JLabel("Please feel free to click anywhere or press any key.");
        fontLabel = new JLabel("Choose a font:");
        fontList = new JList(fontNames);
        fontList.setVisibleRowCount(3);
        fontList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        add(new JScrollPane(fontList));
        boldCb = new JCheckBox("Bold");
        italicCb = new JCheckBox("Italic");
        submitButton = new JButton("Submit");
        mouseLabel = new JLabel("");
        resultLabel = new JLabel("");
        middlePanel = new JPanel();
        middlePanel.setLayout(new FlowLayout());
        bottomPanel = new JPanel();
        bottomPanel.setLayout(new FlowLayout());
        add(insLabel, BorderLayout.NORTH);
        middlePanel.add(fontLabel);
        middlePanel.add(fontList);
        middlePanel.add(boldCb);
        middlePanel.add(italicCb);
        middlePanel.add(submitButton);
        add(middlePanel, BorderLayout.CENTER);
        bottomPanel.add(mouseLabel);
        bottomPanel.add(resultLabel);
        add(bottomPanel, BorderLayout.SOUTH);
        
        // set up event handling
        
        fontList.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                fontName = fontNames[fontList.getSelectedIndex()];
            }
        });
        
        CheckBoxHandler handler = new CheckBoxHandler();
        boldCb.addItemListener(handler);
        italicCb.addItemListener(handler);
        
        submitButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if(fontStyle == "both") {
                    resultLabel.setFont(new Font(fontName, Font.BOLD + Font.ITALIC, 18));
                    resultLabel.setText("You chose " + fontName + " bold and italic");
                } else if(fontStyle == "bold") {
                    resultLabel.setFont(new Font(fontName, Font.BOLD, 18));
                    resultLabel.setText("You chose " + fontName + " bold");
                } else if(fontStyle == "italic") {
                    resultLabel.setFont(new Font(fontName, Font.ITALIC, 18));
                    resultLabel.setText("You chose " + fontName + " italic");
                } else {
                    resultLabel.setFont(new Font(fontName, Font.PLAIN, 18));
                    resultLabel.setText("You chose " + fontName + " plain");
                }
            }
        });
        
        addMouseListener(new MouseClickHandler());
        addMouseMotionListener(new MouseMotionHandler());
        addKeyListener(new KeyHandler());
    } // end constructor
    
    private class CheckBoxHandler implements ItemListener {
        public void itemStateChanged(ItemEvent e) {
            if(boldCb.isSelected() && italicCb.isSelected())
                fontStyle = "both";
            else if(boldCb.isSelected())
                fontStyle = "bold";
            else if (italicCb.isSelected())
                fontStyle = "italic";
            else
                fontStyle = "plain";
        }
    }
    
    private class MouseClickHandler extends MouseAdapter {
        public void mouseClicked(MouseEvent e) {
            int xPos = e.getX();
            int yPos = e.getY();
            mouseLabel.setText("Mouse clicked at (" + xPos + ", " + yPos + ")");
        }
    }
    
    private class MouseMotionHandler extends MouseMotionAdapter {
        public void mouseMoved(MouseEvent e) {
            int xPos = e.getX();
            int yPos = e.getY();
            mouseLabel.setText("Mouse moved at (" + xPos + ", " + yPos + ")");
        }
    }
    
    private class KeyHandler extends KeyAdapter {
        public void keyPressed(KeyEvent e) {
            resultLabel.setText("You pressed " + KeyEvent.getKeyText(e.getKeyCode()));
        }
    }
}
    
    

Java 事件处理 keyevent

评论

1赞 MadProgrammer 5/16/2022
KeyListener臭名昭著,以不回应关键事件而闻名 - 在一些研究中,你会发现它被问了很多。问题是,为了让组件生成 (via ),该组件必须既可聚焦又具有键盘焦点。A不太可能满足这两个要求,再加上你有其他组件的问题,这些组件会“偷走”焦点,你正处于一个永无止境的冲突中。KeyEventKeyListenerJFrame
1赞 MadProgrammer 5/16/2022
解决方案取决于您要解决的问题。通常优先使用键绑定
0赞 MadProgrammer 5/16/2022
这并不是说它“不起作用”,而是它注册到的组件必须是可聚焦的并且具有焦点,因此一旦您单击复选框/按钮/列表,您的面板将失去焦点并且将停止响应 - 这是众所周知的限制KeyListenerKeyListener
0赞 stupidmoron 5/16/2022
@MadProgrammer是的,它有效!!非常感谢您的帮助!我所要做的就是把requestFocusInWindow();在我的 mouseClicked 方法中!
0赞 MadProgrammer 5/16/2022
现在点击一个按钮,看看会发生什么

答:

0赞 MadProgrammer 5/16/2022 #1

KeyListener臭名昭著,以不回应关键事件而闻名 - 在一些研究中,你会发现它被问了很多。问题是,为了让组件生成 (via ),该组件必须既可聚焦又具有键盘焦点。A不太可能满足这两个要求,再加上你有其他组件的问题,这些组件会“偷走”焦点,你正处于一个永无止境的冲突中。KeyEventKeyListenerJFrame

解决方案取决于您要解决的问题。通常优先使用键绑定

举个简单的例子,你可以创建一个可聚焦的组件和监视器,例如......KeyEvents

public class KeyInputPane extends JPanel {

    private JLabel instructionsLabel;
    private JLabel keyLabel;

    public KeyInputPane() {
        setBorder(new CompoundBorder(new LineBorder(Color.GRAY, 1), new EmptyBorder(3, 3, 3, 3)));
        setFocusable(true);

        instructionsLabel = new JLabel("Waiting for focus...");
        keyLabel = new JLabel(" ");

        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridwidth = gbc.REMAINDER;

        add(instructionsLabel, gbc);
        add(keyLabel, gbc);

        addFocusListener(new FocusAdapter() {
            @Override
            public void focusGained(FocusEvent e) {
                setBorder(new CompoundBorder(new LineBorder(Color.BLUE, 1), new EmptyBorder(3, 3, 3, 3)));
                instructionsLabel.setText("Type something");
                keyLabel.setText("...");
            }

            @Override
            public void focusLost(FocusEvent e) {
                setBorder(new CompoundBorder(new LineBorder(Color.GRAY, 1), new EmptyBorder(3, 3, 3, 3)));
                instructionsLabel.setText("Waiting for focus...");
                keyLabel.setText(" ");
            }
        });
        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                requestFocusInWindow();
            }
        });
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyTyped(KeyEvent e) {
                keyLabel.setText(Character.toString(e.getKeyChar()));
            }
        });
    }

}

可运行示例...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new EventsPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class KeyInputPane extends JPanel {

        private JLabel instructionsLabel;
        private JLabel keyLabel;

        public KeyInputPane() {
            setBorder(new CompoundBorder(new LineBorder(Color.GRAY, 1), new EmptyBorder(3, 3, 3, 3)));
            setFocusable(true);

            instructionsLabel = new JLabel("Waiting for focus...");
            keyLabel = new JLabel(" ");

            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = gbc.REMAINDER;

            add(instructionsLabel, gbc);
            add(keyLabel, gbc);

            addFocusListener(new FocusAdapter() {
                @Override
                public void focusGained(FocusEvent e) {
                    setBorder(new CompoundBorder(new LineBorder(Color.BLUE, 1), new EmptyBorder(3, 3, 3, 3)));
                    instructionsLabel.setText("Type something");
                    keyLabel.setText("...");
                }

                @Override
                public void focusLost(FocusEvent e) {
                    setBorder(new CompoundBorder(new LineBorder(Color.GRAY, 1), new EmptyBorder(3, 3, 3, 3)));
                    instructionsLabel.setText("Waiting for focus...");
                    keyLabel.setText(" ");
                }
            });
            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    requestFocusInWindow();
                }
            });
            addKeyListener(new KeyAdapter() {
                @Override
                public void keyTyped(KeyEvent e) {
                    keyLabel.setText(Character.toString(e.getKeyChar()));
                }
            });
        }

    }

    public class EventsPane extends JPanel {
        private JLabel insLabel;
        private JLabel fontLabel;
        private JLabel mouseLabel;
        private JLabel resultLabel;
        private JList fontList;
        private static final String[] fontNames = {"Serif", "SansSerif", "Monospaced"};
        private JCheckBox boldCb;
        private JCheckBox italicCb;
        private JButton submitButton;
        private JPanel middlePanel;
        private JPanel bottomPanel;
        private String fontName;
        private String fontStyle;

        public EventsPane() {
            setLayout(new BorderLayout());
            insLabel = new JLabel("Please feel free to click anywhere or press any key.");
            fontLabel = new JLabel("Choose a font:");
            fontList = new JList(fontNames);
            fontList.setVisibleRowCount(3);
            fontList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            add(new JScrollPane(fontList));
            boldCb = new JCheckBox("Bold");
            italicCb = new JCheckBox("Italic");
            submitButton = new JButton("Submit");
            mouseLabel = new JLabel("");
            resultLabel = new JLabel("");
            middlePanel = new JPanel();
            middlePanel.setLayout(new FlowLayout());
            bottomPanel = new JPanel();
            bottomPanel.setLayout(new FlowLayout());
            add(insLabel, BorderLayout.NORTH);
            middlePanel.add(fontLabel);
            middlePanel.add(fontList);
            middlePanel.add(boldCb);
            middlePanel.add(italicCb);
            middlePanel.add(submitButton);
            middlePanel.add(new KeyInputPane());
            add(middlePanel, BorderLayout.CENTER);
            bottomPanel.add(mouseLabel);
            bottomPanel.add(resultLabel);
            add(bottomPanel, BorderLayout.SOUTH);

            // set up event handling
            fontList.addListSelectionListener(new ListSelectionListener() {
                public void valueChanged(ListSelectionEvent e) {
                    fontName = fontNames[fontList.getSelectedIndex()];
                }
            });

            CheckBoxHandler handler = new CheckBoxHandler();
            boldCb.addItemListener(handler);
            italicCb.addItemListener(handler);

            submitButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    if (fontStyle == "both") {
                        resultLabel.setFont(new Font(fontName, Font.BOLD + Font.ITALIC, 18));
                        resultLabel.setText("You chose " + fontName + " bold and italic");
                    } else if (fontStyle == "bold") {
                        resultLabel.setFont(new Font(fontName, Font.BOLD, 18));
                        resultLabel.setText("You chose " + fontName + " bold");
                    } else if (fontStyle == "italic") {
                        resultLabel.setFont(new Font(fontName, Font.ITALIC, 18));
                        resultLabel.setText("You chose " + fontName + " italic");
                    } else {
                        resultLabel.setFont(new Font(fontName, Font.PLAIN, 18));
                        resultLabel.setText("You chose " + fontName + " plain");
                    }
                }
            });

            addMouseListener(new MouseClickHandler());
            addMouseMotionListener(new MouseMotionHandler());
            addKeyListener(new KeyHandler());
        } // end constructor

        private class CheckBoxHandler implements ItemListener {
            public void itemStateChanged(ItemEvent e) {
                if (boldCb.isSelected() && italicCb.isSelected()) {
                    fontStyle = "both";
                } else if (boldCb.isSelected()) {
                    fontStyle = "bold";
                } else if (italicCb.isSelected()) {
                    fontStyle = "italic";
                } else {
                    fontStyle = "plain";
                }
            }
        }

        private class MouseClickHandler extends MouseAdapter {
            public void mouseClicked(MouseEvent e) {
                int xPos = e.getX();
                int yPos = e.getY();
                mouseLabel.setText("Mouse clicked at (" + xPos + ", " + yPos + ")");
            }
        }

        private class MouseMotionHandler extends MouseMotionAdapter {
            public void mouseMoved(MouseEvent e) {
                int xPos = e.getX();
                int yPos = e.getY();
                mouseLabel.setText("Mouse moved at (" + xPos + ", " + yPos + ")");
            }
        }

        private class KeyHandler extends KeyAdapter {
            public void keyPressed(KeyEvent e) {
                resultLabel.setText("You pressed " + KeyEvent.getKeyText(e.getKeyCode()));
            }
        }
    }
}