所以我将其设置为对 KeyEvents
和计时器的测试。第一次按下右箭头键时,事件将像计时器设置的那样等待 5 秒,然后打印 KeyPressed
。但是,在第一个 println
之后,KeyPressed
将快速连续打印,就像我按住按键时收集的一长串 KeyEvents
一样我不想要所有因按住右箭头键而导致的额外按键。我想按住右箭头键并且每 5 秒只收到一个 println
。任何帮助是极大的赞赏。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
public class GameBoard extends JPanel
{
public Ninja ninja;
public GameBoard()
{
addKeyListener(new TAdapter());
setFocusable(true);
setBackground(Color.BLACK);
setDoubleBuffered(true);
ninja = new Ninja();
}
public void paint(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(ninja.getImage(), 20,20,null);
}
private class TAdapter extends KeyAdapter
{
private Timer timer;
@Override
public void keyPressed(KeyEvent e)
{
timer = new Timer(5000, new ActionListener(){
public void actionPerformed(ActionEvent ae)
{
System.out.println("KeyPressed");
}
});
timer.start();
}
@Override
public void keyReleased(KeyEvent e)
{
ninja.keyReleased(e);
repaint();
}
}
}
最佳答案
当按住该键时,操作系统将为该笔划生成一个重复事件。
通常,您需要某种标志来指示 keyPressed
事件是否已被处理。
根据您的示例,您可以使用计时器
。例如,当触发 keyPressed
时,您将检查 Timer
是否为空或正在运行...
if (timer == null || !timer.isRunning()) {...
现在,在 keyReleased
事件中,您可能需要停止计时器,以便下次触发 keyPressed
时,您可以重新启动计时器。
这假设您只想让计时器在按下按键时运行。
作为一般建议,您应该使用 Key Bindings而不是 KeyListener
,因为它可以让您更好地控制触发按键事件的焦点级别
更新了按键绑定(bind)示例
这基于您的代码似乎正在执行的操作...
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
,它会更新 View 。然后, View 将与模型检查应更新和渲染的内容,并且键绑定(bind)将更新模型的状态,但这只是我的情况。
关于Java swing 计时器仅工作一次,然后 keyEvents 快速连续触发 - 按住键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22748547/