程序不监听 KeyBindings 或 paintComponent()

Program not Listening to KeyBindings or paintComponent()

我有一个程序,每次单击 space 栏时都会发射一颗子弹。但是这个程序有两个问题:它不会调用 paintComponent() 或听我的 KeyBindings。这是我的代码:

import java.awt.Graphics;
import java.awt.event.KeyEvent;

import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;

public class Shoot extends JPanel {

static JFrame frame;

static Ship s1;
static Shoot shoot;

public Shoot() {

    addKeyBinding(KeyEvent.VK_LEFT, "left.pressed", new MoveAction(true, s1, Direction.LEFT), true);
    addKeyBinding(KeyEvent.VK_LEFT, "left.released", new MoveAction(false, s1, Direction.LEFT), false);

    addKeyBinding(KeyEvent.VK_RIGHT, "right.pressed", new MoveAction(true, s1, Direction.RIGHT), true);
    addKeyBinding(KeyEvent.VK_RIGHT, "right.released", new MoveAction(false, s1, Direction.RIGHT), false);

    addKeyBinding(KeyEvent.VK_SPACE, "space.pressed", new MoveAction(true, s1, Direction.SPACE), true);
    addKeyBinding(KeyEvent.VK_SPACE, "space.released", new MoveAction(false, s1, Direction.SPACE), false);

    setDoubleBuffered(true);
}

@Override
public void paintComponent(Graphics g) {
    // Draw the ship
    super.paintComponent(g);
    s1.draw(g);
}

protected void addKeyBinding(int keyCode, String name, Action action, boolean keyPressed) {
    if (keyPressed) {
        addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0, false), name, action);
    } else {
        addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0, true), name, action);
    }
}

protected void addKeyBinding(KeyStroke keyStroke, String name, Action action) {
    InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
    ActionMap actionMap = getActionMap();
    inputMap.put(keyStroke, name);
    actionMap.put(name, action);
}

public static void main(String[] args) {
    // Set the frame up
    frame = new JFrame();
    frame.setSize(400, 300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setResizable(false);
    frame.setVisible(true);

    // Get some more necessary objects
    s1 = new Ship();
    shoot = new Shoot();

    // Threads
    Thread ship = new Thread(s1);
    ship.start();
}
}


import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;

public class Ship implements Runnable {
int x, y, xDirection, bx, by;
boolean readyToFire, shooting = false;
Rectangle bullet;

public Ship() {
    x = 175;
    y = 275;
    bullet = new Rectangle(0, 0, 3, 5);
}

public void draw(Graphics g) {
    g.setColor(Color.BLUE);
    g.fillRect(x, y, 40, 10);
    g.fillRect(x + 18, y - 7, 4, 7);
    if (shooting) {
        g.setColor(Color.RED);
        g.fillRect(bullet.x, bullet.y, bullet.width, bullet.height);
    }
}

public void move() {
    x += xDirection;
    if (x <= 0)
        x = 0;
    if (x >= 360)
        x = 360;
}

public void shoot() {
    if (shooting) {
        bullet.y--;
    }
}

public void setXDirection(int xdir) {
    xDirection = xdir;
}

@Override
public void run() {
    try {
        while (true) {
            shoot();
            move();
            Thread.sleep(5);
        }
    } catch (Exception e) {
        System.err.println(e.getMessage());
    }

}
}


import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.util.HashSet;

import javax.swing.AbstractAction;

public class MoveAction extends AbstractAction {

boolean pressed;
Ship s1;
Direction dir;
private HashSet<Direction> movement;

public MoveAction(boolean pressed, Ship s1, Direction dir) {
    this.pressed = pressed;
    this.s1 = s1;
    this.dir = dir;
}

@Override
public void actionPerformed(ActionEvent e) {
    if (movement.contains(Direction.LEFT)) {
        if (pressed) {
            s1.setXDirection(-1);
        } else {
            s1.setXDirection(0);
        }
    } else if (movement.contains(Direction.RIGHT)) {
        if (pressed) {
            s1.setXDirection(1);
        } else {
            s1.setXDirection(0);
        }
    } else if (movement.contains(Direction.SPACE)) {
        if (pressed) {
            if (s1.bullet == null)
                s1.readyToFire = true;
            if (s1.readyToFire) {
                s1.bullet.x = s1.x + 18;
                s1.bullet.y = s1.y - 7;
                s1.shooting = true;
            }
        } else {
            s1.readyToFire = false;
            if (s1.bullet.y <= -7) {
                s1.bullet = null;
                s1.shooting = false;
                s1.bullet = null;
                s1.bullet = new Rectangle(0, 0, 0, 0);
                s1.readyToFire = true;
            }
        }
    }
}

}

让我们看看你的主要方法:

public static void main(String[] args) {
    // Set the frame up
    frame = new JFrame();
    frame.setSize(400, 300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setResizable(false);
    frame.setVisible(true);

    // Get some more necessary objects
    s1 = new Ship();
    shoot = new Shoot();

    // Threads
    Thread ship = new Thread(s1);
    ship.start();
}

您创建了一个新的 Shoot 对象 -- 但是您把它放在哪里?不在任何显示的 JFrame 中。要使键绑定起作用并使 paintComponent 起作用,绑定和绘图组件必须是显示的 GUI 的一部分——因此将其添加到您的 GUI。

例如,考虑:

public static void main(String[] args) {
    // Set the frame up
    frame = new JFrame();
    frame.setSize(400, 300);  // ** you really don't want to do this
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setResizable(false);

    // Get some more necessary objects
    s1 = new Ship();
    shoot = new Shoot();

    frame.add(shoot);  // ** added to GUI
    frame.setVisible(true);  // ** display GUI **after** addition

此外,根据 camickr 的评论 - 任何时候绘图组件的状态发生变化时都不要忘记调用 repaint() 以改变其绘图。