简体   繁体   English

如何使用箭头键在JPanel中移动对象

[英]how to move an object in a JPanel using the arrow keys

I am trying to create a small program with Windowbuilder that simply paints a red rectangle (called car1) in a JPanel and move it around by pressing the arrow keys; 我正在尝试使用Windowbuilder创建一个小程序,该程序简单地在JPanel中绘制一个红色矩形(称为car1),然后通过按箭头键将其移动。 to do that I associated to the arrows a method to change the x position call the repaint method but the rectangle doesn't move at all - therefore I am probably messing up something with the KeyEvent and/or with repaint. 为此,我将与箭头相关联的更改x位置的方法称为repaint方法,但矩形根本不移动-因此,我可能将KeyEvent和/或repaint弄乱了。

What should I do to make the rectangle each time I press the proper arrow key move and refresh the Panel ? 每次按适当的箭头键移动并刷新面板时,应该怎么做才能使矩形变为矩形?

public class Car extends JPanel {
    int x;
    int y;

    public Car(int x,int y){
        this.x=x;
        this.y=y;
    }


    public void paint(Graphics g) {
        g.setColor(Color.RED);
        g.fillRect(x, y, 20, 20);
    }

    public void move_right(){
        x=x+20;
    }

    public void move_left(){
        x=x-20;
    }

}



public class Form extends JFrame {

    //private JPanel contentPane;
    Car car1;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    Form frame = new Form();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public Form() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 727, 550);
        getContentPane().setLayout(null);
        car1 = new Car(350, 480);
        car1.addKeyListener(new KeyAdapter() {
            public void keyTyped(KeyEvent e) {
                int key = e.getKeyCode();
                if (key == KeyEvent.VK_KP_LEFT) {
                    car1.move_left();
                    car1.repaint();
                }
                if (key == KeyEvent.VK_KP_RIGHT) {
                    car1.move_right();
                    car1.repaint();
                }
            }
        });
        car1.setBounds(0, 0, 700, 500);
        car1.setBackground(new Color(255, 255, 255));
        getContentPane().add(car1);
    }

}

There are at least 3 problems: 至少有3个问题:

  1. Using KeyListener . 使用KeyListener KeyListener is well known for only responding to key events which occur on components which are focusable AND have keyboard focus. KeyListener是众所周知的,它仅响应可聚焦且具有键盘焦点的组件上发生的键事件。 A JPanel by default is not focusable, therefore it can't recieve keyboard focus. 默认情况下, JPanel不能聚焦,因此无法接收键盘焦点。 A better solution is to use the key bindings API, which allows to define the level of focus a component must have before the bindings are triggered and allows you to re-use a Action for multiple keys, reducing code duplication 更好的解决方案是使用键绑定API,该API可以定义触发绑定之前组件必须具有的焦点级别,并允许您将Action用于多个键,从而减少代码重复
  2. Overriding paint . 覆盖paint It's highly recommended to override paintComponent instead of paint when performing custom painting. 强烈建议在执行自定义绘画时重写paintComponent而不是paint。 You've also failed to maintain the paint chain, which is going to cause no end of weird and wonderful paint artifacts. 您还没有维护油漆链,这将不会导致任何奇怪而奇妙的油漆伪影。 Painting in AWT and Swing and Performing Custom Painting for more details 有关更多详细信息,请在AWT和摇摆执行自定义绘画中绘画
  3. Using null layouts. 使用null布局。 Avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. 避免使用null布局,像素完美布局是现代ui设计中的一种幻觉。 There are too many factors which affect the individual size of components, none of which you can control. 有太多因素会影响组件的单个大小,您无法控制。 Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify Swing旨在与布局经理为核心一起工作,舍弃这些问题不会导致问题和问题的终结,您将花费越来越多的时间来尝试纠正

For example... 例如...

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private int xPos;

        public TestPane() {
            Action leftAction = new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    xPos -= 2;
                    if (xPos < 0) {
                        xPos = 0;
                    }
                    repaint();
                }
            };
            Action rightAction = new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    xPos += 2;
                    if (xPos + 10 > getWidth()) {
                        xPos = getWidth() - 10;
                    }
                    repaint();
                }
            };

            bindKeyStroke(WHEN_IN_FOCUSED_WINDOW, "move.left", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), leftAction);
            bindKeyStroke(WHEN_IN_FOCUSED_WINDOW, "move.left", KeyStroke.getKeyStroke(KeyEvent.VK_KP_LEFT, 0), leftAction);
            bindKeyStroke(WHEN_IN_FOCUSED_WINDOW, "move.left", KeyStroke.getKeyStroke(KeyEvent.VK_4, 0), leftAction);
            bindKeyStroke(WHEN_IN_FOCUSED_WINDOW, "move.left", KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), leftAction);

            bindKeyStroke(WHEN_IN_FOCUSED_WINDOW, "move.right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), rightAction);
            bindKeyStroke(WHEN_IN_FOCUSED_WINDOW, "move.right", KeyStroke.getKeyStroke(KeyEvent.VK_KP_RIGHT, 0), rightAction);
            bindKeyStroke(WHEN_IN_FOCUSED_WINDOW, "move.right", KeyStroke.getKeyStroke(KeyEvent.VK_6, 0), rightAction);
            bindKeyStroke(WHEN_IN_FOCUSED_WINDOW, "move.right", KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), rightAction);
        }

        protected void bindKeyStroke(int condition, String name, KeyStroke keyStroke, Action action) {
            InputMap im = getInputMap(condition);
            ActionMap am = getActionMap();

            im.put(keyStroke, name);
            am.put(name, action);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            int yPos = (getHeight() - 10) / 2;
            g2d.drawRect(xPos, yPos, 10, 10);
            g2d.dispose();
        }

    }

}

This is a solution: 这是一个解决方案:

addKeyListener(new KeyAdapter() {
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        if (key == KeyEvent.VK_LEFT) {
            car1.move_left();
            car1.repaint();
        }
        if (key == KeyEvent.VK_RIGHT) {
            car1.move_right();
            car1.repaint();
        }
    }
});

Where are the mistakes: 错误在哪里:

  1. addKeyListener : add key listener to frame, not to panel addKeyListener :将关键侦听器添加到框架,而不是面板
  2. VK_KP_ : use VK_ prefix instead VK_KP_ :改为使用VK_前缀
  3. keyTyped : use keyPressed instead keyTyped :改用keyPressed

Next step you will have to solve is removing the previous rectangles 您必须解决的下一步是删除先前的矩形

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

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