如何使用java中的键移动矩形 [英] How to move a rectangle using keys in java

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

问题描述

我一直试图找出如何使用箭头键移动矩形,但似乎有问题。

我使用 KeyListener 检测所有关键输入。

我不知道如何使用KeyBinding因此我不希望解决方案有它。

我是计划在掌握KeyListener之后立即学习它。请给我关于如何解决它的建议。

I have been trying to find out how to move a rectangle with the arrow keys but there seems to be a problem.
I am using a KeyListener to detect all of the key inputs.
I do not know how to use a KeyBinding therefore I do not wish for the solution to have it.
I am planning to learn it right after mastering KeyListener. Please give me suggestions on how to fix it.

package expo;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Expo extends JPanel implements KeyListener{
    int x = 0; 
    int y = 0;

    @Override
    public void keyTyped(KeyEvent e) {
        //System.out.println("Key Typed");
    }

    @Override
    public void keyPressed(KeyEvent e) {

        if(e.getKeyCode() == KeyEvent.VK_DOWN){
            System.out.println("Key Pressed" + e.getKeyCode());
            y = y + 2;       
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
        //System.out.println("Key Released");
    }

    public void paint(Graphics g){
        g.setColor(Color.BLUE);
        g.drawRect(x ,y,100,100);

        repaint();
    }

    public static void main(String[] args) throws InterruptedException {

        Expo expo = new Expo();
        JFrame f = new JFrame();

        f.setVisible(true);
        f.setSize(500,500);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.addKeyListener(expo);

        f.add(expo);
        f.repaint();           
    }
}


推荐答案


  1. KeyListener 上使用键绑定API,它解决了 KeyListener 遭受的焦点相关问题。 如何使用密钥绑定

  2. 不要破坏油漆链。如果覆盖其中一个 paint 方法,则必须调用它的 super 实现。

  3. 避免重写 paint ,它通常在绘制过程中处于高位,并且由于绘画的工作方式,在绘制子组件时并不总是被调用,会引起一些有趣的问题。 Convention建议改为使用 paintComponent 。请参阅在AWT和Swing中绘画执行自定义绘画以获取更多详细信息

  4. 尝试调用 JFrame #setVisible 最后,在您建立用户界面之后,您会发现它会导致更少的问题

  1. Use the key bindings API over KeyListener, it solves the focus related issues that KeyListener suffers from. How to Use Key Bindings
  2. Don't break the paint chain. If you override one of the paint methods, you must call it's super implementation.
  3. Avoid overriding paint, it's normally to high in the paint process and because of the way painting works, doesn't always get called when a child component is painted, which can cause some interesting issues. Convention recommends using paintComponent instead. See Painting in AWT and Swing and Performing Custom Painting for more details
  4. Try calling JFrame#setVisible last, after you have established the UI, you will find it causes less issues

作为一个例子...

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
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 Expo extends JPanel {

    int x = 0;
    int y = 0;

    public Expo() {
        bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                y += 2;
                if (y + 100 > getHeight()) {
                    y = getHeight() - 100;
                }
                repaint();
            }
        });
        bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                y -= 2;
                if (y < 0) {
                    y = 0;
                }
                repaint();
            }
        });
    }

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

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

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.BLUE);
        g.drawRect(x, y, 100, 100);
    }

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

    public static void main(String[] args) throws InterruptedException {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

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

}

这一切都很酷,一切都很好,但是现在,当你按住键时,矩形会移动,暂停,然后开始稳定地移动!?

That's all cool and everything, but now, when you hold down the key, the rectangle moves, pauses and then begins to move steadily!?

这实际上很正常。相反,你可以做的是建立一个更新循环,它不断监视一组标志的状态,决定在设置这些标志时要做什么并更新UI。

This is actually quite normal. Instead, what you can do, is establish an "update loop" which constantly monitors the state of a set of flags, makes decisions about what to do when those flags are set and updates the UI.

那么,这样做,是设置一个Swing Timer ,它每40毫秒滴答一次,检查当前垂直键状态的状态,更新相应的 y 位置并安排重绘,这样可以让我们更加顺畅,因为我们不依赖于重复键击。

So, what this does, is sets up a Swing Timer which ticks every 40 milliseconds, checks the state of the current "vertical key state", updates the y position accordingly and schedules a repaint, this allows for a much more smoother movement as we're not reliant on the repeating key stroke.

这也证明了键绑定API的强大功能,因为它建立了一个 Action 处理向上和向下移动以及相关的密钥释放...整洁

This also demonstrates the power of the key bindings API, as it establishes a single Action to handle both the up and down movements and the associated key releases...neat

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
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.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Expo extends JPanel {

    int x = 0;
    int y = 0;

    public enum VerticalKey {

        UP, DOWN, NONE;
    }

    public enum HorizontalKey {

        LEFT, RIGHT, NONE;
    }

    private VerticalKey verticalKeyState = VerticalKey.NONE;
    private HorizontalKey horizontalKeyState = HorizontalKey.NONE;

    public Expo() {
        bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "pressed.down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), new VerticalAction(VerticalKey.DOWN));
        bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "released.down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), new VerticalAction(VerticalKey.NONE));
        bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "pressed.up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), new VerticalAction(VerticalKey.UP));
        bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "released.up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), new VerticalAction(VerticalKey.NONE));

        Timer timer = new Timer(40, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                switch (verticalKeyState) {
                    case UP:
                        y -= 2;
                        break;
                    case DOWN:
                        y += 2;
                        break;
                }
                if (y + 100 > getHeight()) {
                    y = getHeight() - 100;
                } else if (y < 0) {
                    y = 0;
                }

                repaint();
            }
        });
        timer.start();
    }

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

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

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.BLUE);
        g.drawRect(x, y, 100, 100);
    }

    public void setVerticalKeyState(VerticalKey verticalKeyState) {
        this.verticalKeyState = verticalKeyState;
        System.out.println(verticalKeyState);
    }

    public void setHorizontalKeyState(HorizontalKey horizontalKeyState) {
        this.horizontalKeyState = horizontalKeyState;
    }

    public class VerticalAction extends AbstractAction {

        private VerticalKey verticalKey;

        public VerticalAction(VerticalKey verticalKeys) {
            this.verticalKey = verticalKeys;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            setVerticalKeyState(verticalKey);
        }

    }

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

    public static void main(String[] args) throws InterruptedException {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

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

}

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

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