How to use KeyListener with JFrame?

后端 未结 4 1708
萌比男神i
萌比男神i 2020-11-30 14:42

So, I was trying to make a rectangle move with a KeyEvent (KeyListener) and whenever I try to hit the key, the rectangle doesn\'t move.

The

相关标签:
4条回答
  • 2020-11-30 15:26

    The rectangle is not moving because you are not using JFrame correctly. You have to assign frame to new mainFrame() instead of ignoring the instantiated mainFrame object.

    There are several other issues as @MadProgrammer points out.

    Here is the code that fixes some of the issues:

    mainFrame.java

    import java.awt.*;
    import java.awt.event.KeyEvent;
    import java.awt.event.KeyListener;
    import javax.swing.JFrame;
    
    
    public class mainFrame extends JFrame implements KeyListener{
        private mainDraw draw;
    
        public void keyPressed(KeyEvent e) {
            System.out.println("keyPressed");
        }
    
        public void keyReleased(KeyEvent e) {
            if(e.getKeyCode()== KeyEvent.VK_RIGHT)
                draw.moveRight();
            else if(e.getKeyCode()== KeyEvent.VK_LEFT)
                draw.moveLeft();
            else if(e.getKeyCode()== KeyEvent.VK_DOWN)
                draw.moveDown();
            else if(e.getKeyCode()== KeyEvent.VK_UP)
                draw.moveUp();
    
        }
        public void keyTyped(KeyEvent e) {
            System.out.println("keyTyped");
        }
    
        public mainFrame(){
            this.draw=new mainDraw();
            addKeyListener(this);
            setFocusable(true);
            setFocusTraversalKeysEnabled(false);
        }
    
        public static void main(String[] args) {
            javax.swing.SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    mainFrame frame = new mainFrame();
                    frame.setTitle("Square Move Practice");
                    frame.setResizable(false);
                    frame.setSize(600, 600);
                    frame.setMinimumSize(new Dimension(600, 600));
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.getContentPane().add(frame.draw);
                    frame.pack();
                    frame.setVisible(true);
                }
            });
        }
    }
    

    mainDraw.java

    import java.awt.Color;
    import java.awt.Graphics;
    import javax.swing.JComponent;
    
    public class mainDraw extends JComponent {
    
        public int x = 50;
        public int y = 50;
    
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawRect(x, y, 50, 50);
            g.fillRect(x, y, 50, 50);
            g.setColor(Color.BLACK);
        }
    
        public void moveRight() {
            x = x + 5;
            repaint();
        }
    
        public void moveLeft() {
            x = x - 5;
            repaint();
        }
    
        public void moveDown() {
            y = y + 5;
            repaint();
        }
    
        public void moveUp() {
            y = y - 5;
            repaint();
        }
    }
    

    BTW, use SwingUtilities to put the gui update code because swing objects are not thread-safe.

    0 讨论(0)
  • 2020-11-30 15:36

    You should add your listener in the mainDraw class, not your mainFrame.

    It's a good practice not to handle key and mouse events in Frames and Windows.

    o/

    0 讨论(0)
  • 2020-11-30 15:37

    There are at least three issues...

    Firstly...

    Your mainFrame class extends from JFrame, but in your main method, you create an instance of it and ignore it, by creating your own JFrame.

    The KeyListener is registered to the instance of mainFrame, meaning, it's been ignored.

    You should get rid of extends JFrame as it's just confusing the issue

    Secondly...

    KeyListener will only respond to key events when the component it is registered to is focusable AND has direct focus, this makes it unreliable.

    Instead, you should use the key bindings API with the Draw panel, this will allow you to over come the focus issues.

    Thirdly...

    You've broken the paint chain, this means that when the rectangle moves, what was painted previously will still remain.

    You should refrain from overriding paint and instead use paintComponent. There are lots of reasons for this, but generally, it paints in the background, is called as updates to child components.

    Finally, make sure you are calling super.paintComponent before you do anything else, to ensure the Graphics context is prepared for painting

    Take a look at Performing Custom Painting for more details

    0 讨论(0)
  • 2020-11-30 15:41

    I was trying to implement shortcut listeners to whole frame and not succeeded, Finally found a way. If you want to set listener even when focus to another component, You must add listeners to all components.

    Here is my code,

    Call this in your constructor :

    setShortcutListener(this); // this = JFrame when you call in in constructor
    

    Method setShortcutListener(JFrame frame) :

    private void setShortcutListener(JFrame frame) {
        List<Component> comp_list = Common.getAllComponents(frame);
        for (Component component : comp_list) {
            component.addKeyListener(getShortcutKeyListener());
        }
    }
    

    Method getAllComponents(frame); Class Common is just a class,

    public static List<Component> getAllComponents(final Container c) {
        Component[] comps = c.getComponents();
        List<Component> compList = new ArrayList<Component>();
        for (Component comp : comps) {
            compList.add(comp);
            if (comp instanceof Container) {
                compList.addAll(getAllComponents((Container) comp));
            }
        }
        return compList;
    }
    

    Method getShortcutKeyListener() :

    public static KeyListener getShortcutKeyListener() {
        KeyListener listener = new KeyListener() {
    
            @Override
            public void keyReleased(KeyEvent evt) {
                if (evt.getKeyCode() == KeyEvent.VK_F3) {
                    // What you do when F3 key pressed
                } else if (evt.getKeyCode() == KeyEvent.VK_F2) {
                    // What you do when F2 key pressed
                } 
            }
    
            @Override
            public void keyTyped(KeyEvent e) {
                // Do nothing
            }
    
            @Override
            public void keyPressed(KeyEvent e) {
                // Do nothing
            }
        };
        return listener;
    }
    

    I think we have easy ways than this, But this code works exactly as expected. Key listeners works anywhere in form.

    Hope this answer will help someone. Thanks.

    0 讨论(0)
提交回复
热议问题