如何才能使多个键绑定起作用?

时间:2014-06-29 18:32:56

标签: java swing paintcomponent keylistener key-bindings

截至目前,我只能让我的一个键绑定一次一个地工作。它通常是第一个创建的。当我按下按键时,每个人都有自己的课程,所以我不明白为什么我的所有按键都不起作用。是因为他们都共享同一个小组吗?目前我有三个动作类,UpAction,PlusAction和MinusAction。 UpAction向上移动矩形,另外两个增加/减小矩形的大小。我遇到的另一个问题是当我向上移动矩形时,当我点击我的增加/减少按钮时,我的向上命令将不再起作用。我是否必须为我的代码写一些内容以重新获得向上箭头键上的焦点?

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.geom.Rectangle2D;

import javax.swing.Icon;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;

import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;


public class Rectangle extends JPanel {

private int height;
private int width;
private int x;
private int y;
private Graphics2D g2;
private Action plusAction;
private Action minusAction;
private Action up;
private static JButton buttonIncrease;
private static JButton buttonDecrease;



public Rectangle(int width, int height,int x, int y)
{
    this.height = height;
    this.width = width;
    this.x = x;
    this.y = y;




    JLabel label = new JLabel();

    buttonIncrease = new JButton(" Increase Size ");
    buttonDecrease = new JButton(" Decrease Size ");

    buttonIncrease.addActionListener(new ButtonListener());
    buttonDecrease.addActionListener(new ButtonListener());
    buttonIncrease.setActionCommand("1");
    buttonDecrease.setActionCommand("2");


    up = new UpAction();
    getInputMap().put(KeyStroke.getKeyStroke("UP"), "doUpAction");
    getActionMap().put("doUpAction", up);

    plusAction = new PlusAction();
    minusAction = new MinusAction();

    buttonIncrease.getInputMap().put(KeyStroke.getKeyStroke(" released Q"), "doPlusAction");
    buttonIncrease.getActionMap().put("doPlusAction", plusAction);


    buttonDecrease.getInputMap().put(KeyStroke.getKeyStroke(" released A"), "doMinusAction");
    buttonDecrease.getActionMap().put("doMinusAction", minusAction);

    add(buttonIncrease);
    add(buttonDecrease);


    label.addKeyListener(new LabelListener());
    label.setFocusable(true);
    label.setOpaque(true);
    this.add(label);
    //label.requestFocusInWindow();
    setVisible(true);





}


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

static class PlusAction extends AbstractAction
{
    //When the plus key is pressed, the increase button
    //will be pressed
    public void actionPerformed(ActionEvent arg0) {
        buttonIncrease.doClick();

    }

}

static class MinusAction extends AbstractAction
{
    //When the minus key is pressed, the decrease button
    //will be pressed
    public void actionPerformed(ActionEvent arg0) {
        buttonDecrease.doClick();

    }

}
 class UpAction extends AbstractAction
{

    public void actionPerformed(ActionEvent e) {
        y = y - 5;
        repaint();
    }

}
// Listener for increasing/decreasing size buttons
 class ButtonListener implements ActionListener{

    public void actionPerformed(ActionEvent e) {

        int action = Integer.parseInt(e.getActionCommand());

        switch(action){
        case 1:
            height = height + 5;
            width = width + 5;
            repaint();
            break;
        case 2:
            height = height - 5;
            width = width - 5;
            repaint();
            break;
        }
    }
 }





class LabelListener implements KeyListener {
public void keyPressed(KeyEvent e)
{   

    if (e.getKeyCode() == KeyEvent.VK_DOWN)
    {
        y = y + 5;
        repaint();
    }
    if (e.getKeyCode() == KeyEvent.VK_LEFT)
    {
        x = x - 5;
        repaint();
    }
    if (e.getKeyCode() == KeyEvent.VK_UP)
    {
        y = y - 5;
        repaint();
    }

    if (e.getKeyCode() == KeyEvent.VK_RIGHT)
    {
        x = x + 5;
        repaint();
    }

}


public void keyReleased(KeyEvent e) {}

public void keyTyped(KeyEvent e) {}


 }

public void paintComponent(Graphics g) {

super.paintComponent(g);
this.g2 = (Graphics2D) g;
g2.drawString("X: " + x,10,20);
g2.drawString("Y: " + y,10,35);
g2.drawString("Width: " + width,10,55);
g2.drawString("Height: " + height,10,70);
g2.drawRect(x, y, width, height);

}

}

测试类:

import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;



public class Test {

 public static void main(String[] args) {


        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI(); 
            }
        });
    }

    private static void createAndShowGUI() {

        JFrame f = new JFrame("Rectangle");


        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(new Rectangle(40,20,250,250));
        f.pack();
        f.setVisible(true);



    }
}

2 个答案:

答案 0 :(得分:4)

结帐Motion Using the KeyboardKeyboardAnimation示例显示了如何让多个KeyStrokes一次工作以提供对角线运动。

基本上你需要跟踪按下了哪些键,然后将每个键的动作加在一起以获得组合动作。

您的代码显然会有所不同,因为您可能需要为每次击键设置不同类型的操作,以保留两个不同的击键图,一个用于运动,另一个用于尺寸更改。然后,每次Timer触发时,您都会分别查询两个映射以确定组合的更改。

答案 1 :(得分:4)

您没有正确设置输入地图的条件:

   private static final int INPUT_CONDITION = JComponent.WHEN_IN_FOCUSED_WINDOW;
   private int height;
   private int width;
   //...

   public Rectangle(int width, int height, int x, int y) {
      // .....

      up = new UpAction();

      // ******** note difference to the getInputMap method below
      getInputMap(INPUT_CONDITION).put(KeyStroke.getKeyStroke("UP"),
            "doUpAction");
      getActionMap().put("doUpAction", up);
      plusAction = new PlusAction();
      minusAction = new MinusAction();
      buttonIncrease.getInputMap(INPUT_CONDITION).put(
            KeyStroke.getKeyStroke("released Q"), "doPlusAction");
      buttonIncrease.getActionMap().put("doPlusAction", plusAction);
      buttonDecrease.getInputMap(INPUT_CONDITION).put(
            KeyStroke.getKeyStroke("released A"), "doMinusAction");

默认的InputMap条件是JComponent.WHEN_FOCUSED,并且键绑定仅在被侦听组件具有焦点时才起作用。在您的情况下,最好将其明确设置为JComponent.WHEN_IN_FOCUSED_WINDOW,现在只要组件位于具有焦点的窗口中,它就会起作用。

您在致电getInputMap时进行了设置。而不是以默认方式getInputMap()调用它,我建议您将其称为getInputMap(INPUT_CONDITION),设置适当的常量。

你在代码中也有KeyListeners - 为什么?拥有Graphics2D或Graphics类字段可能会导致灾难。我将摆脱Graphics2D字段,只需在paintComponent方法或paintComponent调用的方法中使用它。


修改
你问:

  

为什么全局使用Graphics2D会是一件坏事? -

因为拥有变量会使它很有诱惑力,并且如果你在paintComponent之外使用它,你可能会遇到NullPointerException,因为以这种方式从JVM获取的Graphics对象是一个非常短暂的事情。相信我,摆脱那个变量。