所有
我最近对事件处理的工作原理感到困惑。对某人有好处可以给我一些提示,谢谢!
以下是我的理解,为了进行事件处理,有3个步骤: (1)实现监听器(Action,Key,...) (2)提供事件处理程序(actionperformed ...) (3)用源注册听众(这实际上是我困惑的一步)
我看到有人在JPanel对象上执行addKeyListener,而有人在JFrame对象上执行操作。就个人而言,我尝试了两种,有时事件可以处理,有时不能,依赖于哪个JPanel obj。或JFrame obj,我选择addkeylistener。
那么,在什么样的情况下我们可以确定应该使用JPanel还是JPanel,而任何其他对象都会遇到类似的问题?
谢谢!
以下是我尝试制作蛇游戏的练习代码。它还没有完成,但它有我描述的问题,调用addKeyListener将在JFrame上工作,但在JPanel上失败。
Snake.java
package com.snake;
import javax.swing.*;
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.util.ArrayList;
import java.util.Random;
public class Snake implements ActionListener, KeyListener {
public static Snake snake;
public Dimension dimension;
public JFrame jFrame;
public RenderPanel renderPanel;
public ArrayList<Point> snakeParts = new ArrayList<>();
public static final int UP = 0, DOWN = 1, LEFT = 2, RIGHT = 3, SCALE = 10;
public int ticks = 0, direction = DOWN, score, tailLength;
public Point head, cherry;
public Random random;
public boolean hitEdge, putNewCherry;
public Timer timer;
public Snake() {
dimension = Toolkit.getDefaultToolkit().getScreenSize();
jFrame = new JFrame("Snake");
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setSize(500, 500);
jFrame.setLocation((dimension.width - jFrame.getWidth()) / 2, (dimension.height - jFrame.getHeight()) / 2);
jFrame.add(renderPanel = new RenderPanel());
jFrame.addKeyListener(this); // Add Keylistener (1)
jFrame.setFocusable(true);
random = new Random();
cherry = new Point(random.nextInt(jFrame.getWidth()) + 0, random.nextInt(jFrame.getHeight() + 0));
head = new Point(0, 0); // head needs to be instantiated
hitEdge = false;
putNewCherry = true;
timer = new Timer(20, this);
timer.start();
}
// ---------------------------------------------------------------------------- Control the snake by pressing "I, J, K, L"
@Override
public void keyTyped(KeyEvent e) {
// System.out.println("keyPressed="+KeyEvent.getKeyText(e.getKeyCode()));
}
@Override
public void keyPressed(KeyEvent e) {
int i = e.getKeyCode();
if (i == KeyEvent.VK_I && direction != DOWN) {
direction = UP;
System.out.println("UP");
}
if (i == KeyEvent.VK_K && direction != UP) {
direction = DOWN;
System.out.println("DOWN");
}
if (i == KeyEvent.VK_J && direction != RIGHT) {
direction = LEFT;
System.out.println("LEFT");
}
if (i == KeyEvent.VK_L && direction != LEFT) {
direction = RIGHT;
System.out.println("RIGHT");
}
}
@Override
public void keyReleased(KeyEvent e) {
}
// ---------------------------------------------------------------------------- Make the snake moving
@Override
public void actionPerformed(ActionEvent e) {
renderPanel.repaint();
ticks++;
// ---------------------------------------------------------------------------- Determine the direction
if (ticks % 10 == 0 && head != null && hitEdge != true) {
// snakeParts.add(new Point(head.x, head.y));
if (direction == UP) {
if (head.y - 1 > 0) {
// head = new Point(head.x, head.y - 1); // Option (1)
snakeParts.add(new Point(head.x, head.y--)); // OPtion (2), can be replaced by (1)
} else {
hitEdge = true;
}
}
if (direction == DOWN) {
if (head.y + 1 < dimension.height / SCALE) {
// head = new Point(head.x, head.y + 1); // Option (1)
snakeParts.add(new Point(head.x, head.y++)); // OPtion (2), can be replaced by (1)
} else {
hitEdge = true;
}
}
if (direction == LEFT) {
if (head.x - 1 > 0) {
// head = new Point(head.x - 1, head.y); // Option (1)
snakeParts.add(new Point(head.x--, head.y)); // OPtion (2), can be replaced by (1)
} else {
hitEdge = true;
}
}
if (direction == RIGHT) {
if (head.x + 1 < dimension.width / SCALE) {
// head = new Point(head.x + 1, head.y); // Option (1)
snakeParts.add(new Point(head.x++, head.y)); // OPtion (2), can be replaced by (1)
} else {
hitEdge = true;
}
}
// snakeParts.add(new Point(head.x, head.y)); // Option (1)
// ---------------------------------------------------------------------------- Remove the tail part each time to maintain the whole body length as the same
snakeParts.remove(0);
// Each a cherry, gain longer length, get score
if (cherry != null && head.equals(cherry)) {
score += 100;
tailLength++;
// Reset the cherry's location == put a new cherry.
cherry.setLocation(random.nextInt(jFrame.getWidth()) + 0, random.nextInt(jFrame.getHeight() + 0));
}
// ----------------------------------------------------------------------------
}
}
}
RenderPanel.java
import javax.swing.*;
import java.awt.*;
public class RenderPanel extends JPanel {
// public static int cherryX, cherryY;
// // Instantiate the RenderPanel to register the Snake as KeyListerner
// public RenderPanel(){
// addKeyListener(Snake.snake); // Add Keylistener (1) ???
// setFocusable(true);
// System.out.println("Call RenderPanel");
// }
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// Paint the background
g.setColor(color.BLACK);
g.fillRect(0, 0, 500, 500);
// Pain the snake body
Snake snake = Snake.snake;
g.setColor(color.WHITE); // Assign the new color to the snake's body
for (Point snakePart : snake.snakeParts) { // Loop to paint each part of the snake body
g.fillRect(snakePart.x * snake.SCALE, snakePart.y * snake.SCALE, snake.SCALE, snake.SCALE);
}
g.fillRect(snake.head.x * snake.SCALE, snake.head.y * snake.SCALE, snake.SCALE, snake.SCALE);
g.setColor(color.RED);
g.fillRect(snake.cherry.x, snake.cherry.y, snake.SCALE, snake.SCALE);
}
}
Main.java
public class Main {
public static void main(String[] args) {
Snake.snake = new Snake();
}
}