Java 摆动计时器只工作一次,然后 keyEvents 快速连续触发 - 按住键 [英] Java swing timer only works once then keyEvents fire in rapid succession - holding key down

查看:27
本文介绍了Java 摆动计时器只工作一次,然后 keyEvents 快速连续触发 - 按住键的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我将其设置为对 KeyEvents 和计时器的测试.第一次按下右箭头键时,事件将等待 5 秒,就像计时器设置的那样,然后打印 KeyPressed.然而,在第一个 println 之后,KeyPressed 将快速连续打印,就像一长串 KeyEvents 在我按住键时它正在收集下来.我不希望按住右箭头键导致的所有额外按键.我想按住右箭头键,每 5 秒只收到一个 println .任何帮助是极大的赞赏.

So I've set this up as a test for KeyEvents and timers. The first time the right arrow key is pressed the event will wait 5 seconds like the timer is setup to, then print KeyPressed. However, after the first println, KeyPressed will be printed in rapid succession like a long queue of KeyEvents it was collecting up while I held the key down.I don't want all the extra key presses that holding the right arrow key causes. I want to hold the right arrow key down and only receive a println every 5 seconds. Any help is greatly appreciated.

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();
    }

}
}

推荐答案

当按键被按下时,操作系统会为笔画生成一个重复事件.

When the key is held down, the OS will generate a repeating event for the stroke.

通常,您需要某种标志来指示 keyPressed 事件是否已被处理.

Normally, you would need some kind of flag that would indicate that the keyPressed event has already been handled or not.

根据您的示例,您可以使用 Timer.例如,当 keyPressed 被触发时,您将检查 Timer 是否为空或正在运行...

Based on your example, you could use the Timer. For example, when keyPressed is triggered, you would check to see of the Timer is null or is running...

if (timer == null || !timer.isRunning()) {...

现在,在您的 keyReleased 事件中,您可能需要停止计时器,以便下次触发 keyPressed 时,您可以重新启动计时器.

Now, in your keyReleased event, you could need to stop the timer, so that the next time keyPressed is triggered, you can restart the timer.

这假设您只希望计时器仅在按键被按下时运行.

This assumes that you only want the timer to run only while the key is pressed.

作为一般建议,您应该使用键绑定 而不是 KeyListener 因为它可以让您更好地控制触发关键事件的焦点级别

As a general suggestion, you should be using Key Bindings instead of KeyListener as it will provide you better control over the focus level which triggers the key events

更新了键绑定示例

这是基于您的代码似乎在做什么...

This is based on what your code appears to be doing...

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,它总是在滴答作响,更新视图.然后,视图会与模型核对应该更新和呈现的内容,并且键绑定会更新模型的状态,但这只是我自己.

Personally, I would have a single Timer which was always ticking, which updated the view. The view would then check with the model about what should be updated and rendered and the key bindings would update the state of the model, but that's just me.

这篇关于Java 摆动计时器只工作一次,然后 keyEvents 快速连续触发 - 按住键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆