Java-键绑定无效/未调用actionPerformed函数

3
我终于学会了如何在Java中使用图形,感谢帮助我解答上一篇问题的人,但是现在我无法使按键绑定(key bindings)工作。我知道需要调用图形方法,我认为我已经正确声明了按键绑定,但是“actionPerformed()”方法没有被调用。我尝试使用单例模式将我的玩家对象跨类传递,并且我觉得它在某种程度上破坏了其他所有东西。我尝试查看很多与我的问题相关的其他问题,但是我仍然无法解决,除非我忽略了一些明显的事情。如果你们伟大的编程巨匠中有人能够解决这个问题,我真的非常感激!
import java.net.URL;

import javax.swing.ImageIcon;
import javax.swing.KeyStroke;

public class Player {
    private int xLoc, yLoc;
    private boolean isFiring;
    private String filename;
    private ImageIcon imageicon;
    private URL imgURL;

    private static Player player;

    public Player(int xl, int yl, boolean fire, String name){
        xLoc = xl;
        yLoc = yl;
        isFiring = fire;
        filename = name;
        imgURL = getClass().getResource(name);
        imageicon = new ImageIcon(imgURL);
    }

    public static Player getInstance(){
        if(player == null){
            player = new Player(0,0,false,"Dog.jpg");
        }
        return player;
    }

    public void fire(){

    }

    public int getX(){
        return xLoc;
    }
    public int getY(){
        return yLoc;
    }
    public void newX(int x){
        xLoc = x;
    }
    public ImageIcon getImg() {
        return imageicon;
    }
    public void newImg(ImageIcon ii){
        imageicon = ii;
    }
    public URL getURL(){
        return imgURL;
    }
    public void newURL(String n){
        imgURL = getClass().getResource(n);
    }
    public void updateObject(){
        imageicon = new ImageIcon(imgURL);
    }
}

.

import java.awt.Graphics;
import java.net.URL;

import javax.swing.JPanel;
import javax.swing.KeyStroke;

public class GamePanel extends JPanel{
    int nameSwap = 0;
    Player player;
    public GamePanel(){
        player = Player.getInstance();
        repaint();
        System.out.println("Repaint method called");

        this.getInputMap().put(KeyStroke.getKeyStroke("A"), "moveLeft");
        this.getActionMap().put("moveLeft", new MoveLR(-1));

        this.getInputMap().put(KeyStroke.getKeyStroke("D"), "moveRight");
        this.getActionMap().put("moveRight", new MoveLR(1));

        this.getInputMap().put(KeyStroke.getKeyStroke("S"), "fire");
        this.getActionMap().put("fire", new Fire());
    }
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.drawImage(player.getImg().getImage(), player.getX(), player.getY(), 50, 50, null);
        //System.out.println("Graphics method called");
    }
}

.

import java.awt.Color;

import javax.swing.JFrame;

public class Window {

    public Window() {
        JFrame frame = new JFrame("Epic Game");
        frame.setSize(800,600);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        GamePanel panel = new GamePanel();
        frame.add(panel);

        frame.setVisible(true);

        while(true){
            panel.repaint();
        }
    }

    public static void main(String[] args){
        Window window = new Window();
    }
}   

.

import java.awt.event.ActionEvent;
import java.beans.PropertyChangeListener;

import javax.swing.Action;

public class MoveLR implements Action{
    private int moveVal;
    Player player;
    public MoveLR(int mv){
        moveVal = mv;
        player = Player.getInstance();
        System.out.println("New MoveLR object made");
    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        // TODO Auto-generated method stub
        player.newX(player.getX() + 1);
        System.out.println("actionPerformed() called");
    }

    @Override
    public void addPropertyChangeListener(PropertyChangeListener arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public Object getValue(String arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public boolean isEnabled() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public void putValue(String arg0, Object arg1) {
        // TODO Auto-generated method stub

    }

    @Override
    public void removePropertyChangeListener(PropertyChangeListener arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void setEnabled(boolean arg0) {
        // TODO Auto-generated method stub

    }
}

while(true) panel.repaint() ... 你真的不喜欢你的用户... - MadProgrammer
这是什么问题?我以前从未听说过不要这样做的事情 @MadProgrammer - Neeek
  1. 为了更快地获得帮助,请发布一个MCVE(Minimal Complete Verifiable Example)或SSCCE(Short,Self Contained,Correct Example)。
  2. 获取示例图像的一种方法是热链接到在此Q&A中看到的图像。
- Andrew Thompson
你基本上没有给Thread时间去“休眠”,这意味着它将继续占用CPU,这可能会降低程序的效率,特别是在负载增加时。使用Thread.sleep甚至Thread.yield可以让系统有些喘息的空间。重绘不是一项简单的任务 ;) - MadProgrammer
啊,好的,谢谢你的建议。另外,你有没有想过为什么我的actionPerformed()方法可能还没有被调用呢?我已经按照@Hovercraft Full Of Eels所说的添加了JComponent.WHEN_IN_FOCUSED_WINDOW部分了。 - Neeek
1个回答

4

您使用的是错误的InputMap。请使用getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)。这样,您将绑定到在JPanel没有焦点但显示在具有焦点的窗口中的活动键。默认InputMap是用于JComponent.WHEN_FOCUSED的输入映射,这仅在绑定组件具有焦点时才有效,而这不是您想要做或使用的。

this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("A"), 
        "moveLeft");

请使用继承自AbstractAction的类,而不是实现Action接口的类,因为您的操作没有完全连接。同时,在actionPerformed方法的结尾处进行重绘是可行的,只要您有对JPanel的引用,该ActionEvent可以让您获得该引用。

测试程序:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;

import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;

public class Window {

   public Window() {
      JFrame frame = new JFrame("Epic Game");
      frame.setSize(800, 600);
      frame.setLocationRelativeTo(null);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

      GamePanel panel = new GamePanel();
      frame.add(panel);

      frame.setVisible(true);

      // !! while (true) {
      // panel.repaint();
      // }
   }

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

@SuppressWarnings("serial")
class GamePanel extends JPanel {
   int nameSwap = 0;
   Player player;

   public GamePanel() {
      player = Player.getInstance();
      repaint();
      System.out.println("Repaint method called");

      this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("A"), "moveLeft");
      this.getActionMap().put("moveLeft", new MoveLR(-1));

      this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("D"), "moveRight");
      this.getActionMap().put("moveRight", new MoveLR(1));

      this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("S"), "fire");
      this.getActionMap().put("fire", new Fire());
   }

   public void paintComponent(Graphics g) {
      super.paintComponent(g);
      g.drawImage(player.getImg().getImage(), player.getX(), player.getY(), 50,
            50, null);
      // System.out.println("Graphics method called");
   }
}

class Player {
   private int xLoc, yLoc;
   private boolean isFiring;
   private String filename;
   private ImageIcon imageicon;
   // !! private URL imgURL;

   private static Player player;

   public Player(int xl, int yl, boolean fire, String name) {
      BufferedImage img = new BufferedImage(20, 20, BufferedImage.TYPE_INT_ARGB);
      Graphics2D g2 = img.createGraphics();
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
      g2.setColor(Color.red);
      g2.fillOval(2, 2, 16, 16);
      g2.dispose();
      imageicon = new ImageIcon(img);
      xLoc = xl;
      yLoc = yl;
      isFiring = fire;
      filename = name;
      // !! imgURL = getClass().getResource(name);
      // imageicon = new ImageIcon(imgURL);
   }

   public static Player getInstance() {
      if (player == null) {
         player = new Player(0, 0, false, "Dog.jpg");
      }
      return player;
   }

   public void fire() {

   }

   public int getX() {
      return xLoc;
   }

   public int getY() {
      return yLoc;
   }

   public void newX(int x) {
      xLoc = x;
   }

   public ImageIcon getImg() {
      return imageicon;
   }

   public void newImg(ImageIcon ii) {
      imageicon = ii;
   }

   // !! public URL getURL(){
   // return imgURL;
   // }
   // !! public void newURL(String n){
   // imgURL = getClass().getResource(n);
   // }
   public void updateObject() {
      // !! imageicon = new ImageIcon(imgURL);
      System.out.println("update object called");
   }
}

class MoveLR extends AbstractAction {
   private int moveVal;
   Player player;

   public MoveLR(int mv) {
      moveVal = mv;
      player = Player.getInstance();
      System.out.println("New MoveLR object made");
   }

   @Override
   public void actionPerformed(ActionEvent e) {
      // TODO Auto-generated method stub
      player.newX(player.getX() + moveVal);
      ((JPanel) e.getSource()).repaint();
      System.out.println("actionPerformed() called");
   }

}

class Fire extends AbstractAction {
   public Fire() {
      System.out.println("Fire created");
   }

   @Override
   public void actionPerformed(ActionEvent arg0) {
      System.out.println("Fire called");
   }
}

我已经更改了所有的键绑定,但它仍然无法工作。或许我也应该把那个加上去,所以谢谢提醒。 - Neeek
@Neeek:同时,Mad也提出了一个很好的观点--这个while (true)方法在这里没有用处。使用键绑定来移动或使用Swing计时器。 - Hovercraft Full Of Eels
我该如何使用绑定来移动,也许在actionPerformed()方法的末尾调用repaint()?但我仍然无法让键绑定响应。@Hovercraft Full Of Eels - Neeek
@Neeek:同时使用扩展AbstractActions的类,而不是实现Action的类,因为你的Actions没有完全连接。是的,在actionPerformed的末尾可以重绘,只要你有对JPanel的引用,而ActionEvent可以帮助你获取它。 - Hovercraft Full Of Eels
非常感谢您的帮助,示例代码非常准确。 - Neeek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接