如何使用箭头键在JPanel中移动对象 [英] how to move an object in a JPanel using the arrow keys

查看:94
本文介绍了如何使用箭头键在JPanel中移动对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Windowbuilder创建一个小程序,该程序简单地在JPanel中绘制一个红色矩形(称为car1),然后通过按箭头键将其移动.为此,我将与箭头关联的更改x位置的方法称为repaint方法,但矩形根本不移动-因此,我可能将KeyEvent和/或repaint弄乱了.

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; 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.

每次按下适当的箭头键并刷新面板时,我应该怎么做才能制作矩形?

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

}

推荐答案

至少存在3个问题:

  1. 使用KeyListener. KeyListener以仅响应按键事件而闻名,这些按键事件发生在可聚焦且具有键盘焦点的组件上.默认情况下,JPanel不能聚焦,因此它不能接收键盘焦点.更好的解决方案是使用键绑定API,该API可以定义触发绑定之前组件必须具有的焦点级别,并允许您将Action重用于多个键,从而减少代码重复
  2. 覆盖paint.强烈建议在执行自定义绘画时重写paintComponent而不是绘画.您还没有维护油漆链,这将不会导致任何奇怪而奇妙的油漆伪影. AWT和Swing中的绘画
  1. Using KeyListener. KeyListener is well known for only responding to key events which occur on components which are focusable AND have keyboard focus. A JPanel by default is not focusable, therefore it can't recieve keyboard focus. 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
  2. Overriding paint. It's highly recommended to override paintComponent instead of paint when performing custom painting. 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
  3. Using null layouts. Avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. 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

例如...

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

    }

}

这篇关于如何使用箭头键在JPanel中移动对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆