【问题标题】:KeyBinding for multiple arrow key press多个箭头键按下的键绑定
【发布时间】:2015-07-08 19:09:11
【问题描述】:

此代码是否适合多个箭头键按下。它现在正在工作。向右走,向左走。但是,如果我同时按下左右箭头键,我希望这个桨停止。我怎样才能做到这一点 ?

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class GamePanel extends JPanel {

// ENUM     
public enum HorizontalMovement {
    NONE,
    LEFT,
    RIGHT
}

// CONSTANTS    
private static final int WIDTH = 600;
private static final int HEIGHT = 500;
private static final int PADDLE_Y = 475;
private static final int PADDLE_W = 80;
private static final int PADDLE_H = 20;
private static final int PADDLE_ARC = 15;       

// PROPERTIES   
int x = 0;  
private HorizontalMovement horizontalMovement = HorizontalMovement.NONE;
private Timer timer;

// CONSTRUCTOR  
public GamePanel() {

    setSize(WIDTH, HEIGHT);
    setBackground(new Color(240, 255, 255));

    // right pressed

    KeyStroke ks1 = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false);

    InputMap im1 = getInputMap(WHEN_IN_FOCUSED_WINDOW);
    ActionMap am1 = getActionMap();

    im1.put(ks1, "right.pressed");
    am1.put("right.pressed", new MoveHorizontialAction(HorizontalMovement.RIGHT));


    // right released

    KeyStroke ks2 = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true);

    InputMap im2 = getInputMap(WHEN_IN_FOCUSED_WINDOW);
    ActionMap am2 = getActionMap();

    im2.put(ks2, "right.relesed");
    am2.put("right.relesed", new MoveHorizontialAction(HorizontalMovement.NONE));

    // left pressed

    KeyStroke ks3 = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false);

    InputMap im3 = getInputMap(WHEN_IN_FOCUSED_WINDOW);
    ActionMap am3 = getActionMap();

    im3.put(ks3, "left.pressed");
    am3.put("left.pressed", new MoveHorizontialAction(HorizontalMovement.LEFT));

    // left released

    KeyStroke ks4 = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true);

    InputMap im4 = getInputMap(WHEN_IN_FOCUSED_WINDOW);
    ActionMap am4 = getActionMap();

    im4.put(ks4, "left.relesed");
    am4.put("left.relesed", new MoveHorizontialAction(HorizontalMovement.NONE));


    // each 15 ms       
    timer = new Timer(15, new TimeListener());
    timer.start();

}

// PADDLE 
@Override
protected void paintComponent(Graphics g) {

    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g;

    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
          RenderingHints.VALUE_ANTIALIAS_ON);

    g.setColor(new Color(201, 51, 51));
    g.fillRoundRect(x, PADDLE_Y, PADDLE_W, PADDLE_H, PADDLE_ARC, PADDLE_ARC);   
 }

// Time Listener

protected class TimeListener implements ActionListener {

    @Override
    public void actionPerformed(ActionEvent e) {

        if ( horizontalMovement == HorizontalMovement.RIGHT )
            x = x + 2;

        if ( horizontalMovement == HorizontalMovement.LEFT )
            x = x - 2;

        if ( x < 0 ) 
            x = 0;
        else if ( x > 520 ) 
            x = 520;

        repaint();
    }

}

// ACTION FOR ActionMap
protected class MoveHorizontialAction extends AbstractAction {

    private HorizontalMovement movement;

    public MoveHorizontialAction(HorizontalMovement movement) {
        this.movement = movement;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        horizontalMovement = movement;
    }
}   
}

主要代码:

import java.awt.*;
import javax.swing.*;

public class MainFrame extends JFrame{

public MainFrame() {

    // size
    setSize(600, 500);
    setLocationRelativeTo(null);
    setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE);    


    // remove borders
    setUndecorated(true);
    getRootPane().setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, new Color(63, 134, 145)));

    getContentPane().add( new GamePanel());

    setVisible(true);       
}

public static void main(String[] args) {

    new MainFrame();        
}
}

【问题讨论】:

    标签: java swing key-bindings keystroke


    【解决方案1】:

    只有在它处于NONE状态时才链接方向怎么办,或者它应该处于NONE状态

    如果你按左键,它将是:

    NONE->LEFT, LEFT
    

    然后你按右:

    LEFT->NONE, RIGHT
    

    所以它会停止

    @Override
    public void actionPerformed(ActionEvent e) {
        if(horizontalMovement==HorizontalMovement.NONE ||
                     movement==HorizontalMovement.NONE){
            horizontalMovement = movement;
        }else{
            horizontalMovement = HorizontalMovement.NONE;
        }
    }
    

    未经测试,只是一个想法

    EDIT固定平滑

    为了平滑的运动,我使用了运动的 HashSet,它包含所有活动的运动,所以如果它包含 两个运动(右+左),两个都会被使用,这会导致:

    if ( movements.contains(HorizontalMovement.RIGHT) )
        x = x + 2;
    if ( movements.contains(HorizontalMovement.LEFT) )
        x = x - 2;
    

    两个条件都满足,x 留在x=(x+2)-2

    此处的完整代码(GamePanel 类、MainFrame 没有编辑):

    import java.awt.*;
    import javax.swing.*;
    import java.awt.event.*;
    import java.util.HashSet;
    public class GamePanel extends JPanel {
    
        // ENUM     
        public enum HorizontalMovement {
            NONE,
            LEFT,
            RIGHT
        }
    
        // CONSTANTS    
        private static final int WIDTH = 600;
        private static final int HEIGHT = 500;
        private static final int PADDLE_Y = 475;
        private static final int PADDLE_W = 80;
        private static final int PADDLE_H = 20;
        private static final int PADDLE_ARC = 15;
        private HashSet<HorizontalMovement> movements = new HashSet<HorizontalMovement>();
    
        // PROPERTIES   
        int x = 0;
        private Timer timer;
    
        // CONSTRUCTOR  
        public GamePanel() {
    
            setSize(WIDTH, HEIGHT);
            setBackground(new Color(240, 255, 255));
    
            // right pressed
    
            KeyStroke ks1 = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false);
    
            InputMap im1 = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap am1 = getActionMap();
    
            im1.put(ks1, "right.pressed");
            am1.put("right.pressed", new MoveHorizontialAction(true,HorizontalMovement.RIGHT));
    
            // right released
            KeyStroke ks2 = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true);
            InputMap im2 = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap am2 = getActionMap();
    
            im2.put(ks2, "right.relesed");
            am2.put("right.relesed", new MoveHorizontialAction(false,HorizontalMovement.RIGHT));
    
            // left pressed
    
            KeyStroke ks3 = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false);
    
            InputMap im3 = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap am3 = getActionMap();
    
            im3.put(ks3, "left.pressed");
            am3.put("left.pressed", new MoveHorizontialAction(true,HorizontalMovement.LEFT));
    
            // left released
    
            KeyStroke ks4 = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true);
    
            InputMap im4 = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap am4 = getActionMap();
    
            im4.put(ks4, "left.relesed");
            am4.put("left.relesed", new MoveHorizontialAction(false,HorizontalMovement.LEFT));
    
            // each 15 ms       
            timer = new Timer(15, new TimeListener());
            timer.start();
    
        }
    
        // PADDLE 
        @Override
        protected void paintComponent(Graphics g) {
    
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g;
    
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
    
            g.setColor(new Color(201, 51, 51));
            g.fillRoundRect(x, PADDLE_Y, PADDLE_W, PADDLE_H, PADDLE_ARC, PADDLE_ARC);   
        }
    
        // Time Listener
    
        protected class TimeListener implements ActionListener {
    
            @Override
            public void actionPerformed(ActionEvent e) {
    
                if ( movements.contains(HorizontalMovement.RIGHT) )
                    x = x + 2;
    
                if ( movements.contains(HorizontalMovement.LEFT) )
                    x = x - 2;
    
                if ( x < 0 ) 
                    x = 0;
                else if ( x > 520 ) 
                    x = 520;
    
                repaint();
            }
    
        }
    
        // ACTION FOR ActionMap
        protected class MoveHorizontialAction extends AbstractAction {
    
            private HorizontalMovement movement;
            private boolean add=true;
            public MoveHorizontialAction(boolean add,HorizontalMovement movement) {
                this.movement = movement;
                this.add = add;
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                if(add){
                    //System.out.println("Add: "+movement.name());
                    movements.add(movement);
                }else{
                    //System.out.println("Rem: "+movement.name());
                    movements.remove(movement);
                }
            }
        }   
    }
    

    不要害怕询问有关此代码的问题

    【讨论】:

    • 是的。就是这样。在 KeyListener 版本中,我能够使用布尔值进行多次按键操作。但在 keyBindings 中。我不能。我现在知道了。谢谢。我最好多练习一下 KeyBindings
    • KeyListeners 比这更好(更多变量),你必须使用 keyBindings 吗? @cihangirND
    • 没有。但是,当我在旧帖子中看到 cmets 时,人们说键绑定在这类项目中更实用。
    • 它们很小,易于实现,但不如 KeyListener 有用(我的观点)@cihangirND
    • 好的。现在我将使用具有 maskacovnik 逻辑的 keylistener 来完成。 (使用哈希集、布尔值等)