当按键被按住时,操作系统会为笔画生成一个重复事件。
通常,您需要某种标志来指示keyPressed 事件是否已被处理。
根据您的示例,您可以使用Timer。例如,当keyPressed 被触发时,您会检查Timer 是否为空或正在运行...
if (timer == null || !timer.isRunning()) {...
现在,在您的keyReleased 事件中,您可能需要停止计时器,以便下次触发keyPressed 时,您可以重新启动计时器。
这假设您只希望计时器仅在按键被按下时运行。
作为一般建议,您应该使用Key Bindings 而不是KeyListener,因为它可以让您更好地控制触发关键事件的焦点级别
更新了键绑定示例
这取决于您的代码似乎在做什么......
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class WalkCycle {
public static void main(String[] args) {
new WalkCycle();
}
public WalkCycle() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private List<BufferedImage> walkCycle;
private int frame;
private Timer timer;
public TestPane() {
setBackground(Color.WHITE);
walkCycle = new ArrayList<>(10);
try {
walkCycle.add(ImageIO.read(getClass().getResource("/Walk01.png")));
walkCycle.add(ImageIO.read(getClass().getResource("/Walk02.png")));
walkCycle.add(ImageIO.read(getClass().getResource("/Walk03.png")));
walkCycle.add(ImageIO.read(getClass().getResource("/Walk04.png")));
walkCycle.add(ImageIO.read(getClass().getResource("/Walk05.png")));
walkCycle.add(ImageIO.read(getClass().getResource("/Walk06.png")));
walkCycle.add(ImageIO.read(getClass().getResource("/Walk07.png")));
walkCycle.add(ImageIO.read(getClass().getResource("/Walk08.png")));
walkCycle.add(ImageIO.read(getClass().getResource("/Walk09.png")));
walkCycle.add(ImageIO.read(getClass().getResource("/Walk10.png")));
Timer timer = new Timer(80, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
frame++;
if (frame >= walkCycle.size()) {
frame = 0;
}
System.out.println(frame);
repaint();
}
});
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "right-down");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), "right-up");
am.put("right-down", new TimerAction(timer, true));
am.put("right-up", new TimerAction(timer, false));
} catch (IOException exp) {
exp.printStackTrace();
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics g2d = (Graphics2D) g.create();
BufferedImage img = walkCycle.get(frame);
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
g2d.drawImage(img, x, y, this);
g2d.dispose();
}
}
public class TimerAction extends AbstractAction {
private Timer timer;
private boolean start;
public TimerAction(Timer timer, boolean start) {
this.timer = timer;
this.start = start;
}
@Override
public void actionPerformed(ActionEvent e) {
if (start && !timer.isRunning()) {
System.out.println("Start");
timer.start();
} else if (!start && timer.isRunning()) {
System.out.println("stop");
timer.stop();
}
}
}
}
就我个人而言,我会有一个Timer,它总是在滴答作响,从而更新了视图。然后视图将与模型检查应该更新和呈现的内容,并且键绑定将更新模型的状态,但这只是我。