Java swing 计时器仅工作一次,然后 keyEvents 快速连续触发 - 按住键

标签 java swing timer actionlistener keylistener

所以我将其设置为对 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)示例

这基于您的代码似乎正在执行的操作...

Walkies

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/

相关文章:

在 C 中计算时间跨度

javascript - 在JQuery Timer中添加时间按钮

java - setter 和 getter 方法无法识别

java.io.File 在写入文件时获取额外的字符

java - Intellij 使用另一个类的数组创建组合框

java - GridLayout 面板上的面板

德尔福定时器: Time before next event

java - 使用javaFX编译并运行

java - 如何阻止应用程序退出后出现插页式广告?

java - JFrame 的半透明加载覆盖