【问题标题】:Java swing timer only works once then keyEvents fire in rapid succession - holding key downJava swing timer 只工作一次,然后 keyEvents 快速连续触发 - 按住键
【发布时间】:2014-05-10 00:33:18
【问题描述】:

所以我将其设置为对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();
    }

}
}

【问题讨论】:

  • 您将希望使用 Key Bindings,而不是 KeyListener,并且希望绑定到最后具有布尔参数的 KeyStroke,已释放。请参阅我的回答 here 了解更多信息和工作代码示例。
  • 我只想对所有的答案和回复表示感谢。我非常感谢所有的意见,因为每一点都拓宽了我对编程的看法。

标签: java swing timer actionlistener keylistener


【解决方案1】:

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

通常,您需要某种标志来指示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,它总是在滴答作响,从而更新了视图。然后视图将与模型检查应该更新和呈现的内容,并且键绑定将更新模型的状态,但这只是我。

【讨论】:

  • 看起来我想要的对于 Key Listeners 根本不可能实现,因此我需要开始使用 Key Bindings。我已经尝试了所有我能想到的方法,包括外部和内部计时器。在按住箭头键的同时使用一堆图像为角色设置动画是没有任何作用的。无论我做什么,从按住键开始的 20 个关键事件最终都会突破并弄乱动画。
  • 我看看能不能稍后整理一个例子
【解决方案2】:

当您按住某个键时,keyPressed 事件将快速连续发生。你所做的就是给这波事件增加了 5 秒的延迟。

解决此问题取决于您要执行的操作。如果您只想让事件每 5 秒发生一次,您可以将计时器移到事件之外,然后当事件被调用时,根据计时器每 5 秒切换一次的布尔值检查是否经过了 5 秒。

【讨论】:

  • 好吧,看看我要做的是在按下右箭头键时通过连续触发 3 个图像来创建动画。为此,我需要在图像 repaint() 之间设置一个计时器,但是当我按住键时,计时器将不存在,并且图像会变成非常快速移动的图像模糊。
【解决方案3】:

这将解决您的问题。

不需要计时器

它是系统当前时序的简单用途...

private long startTime;

private class TAdapter extends KeyAdapter {
    public void keyPressed(final KeyEvent e) {

        if (System.currentTimeMillis() - startTime > 2000) {
            startTime = System.currentTimeMillis();
            ninja.keyPressed(e, 1);
            repaint();
        } else if (System.currentTimeMillis() - startTime > 1000) {
            ninja.keyPressed(e, 2);
            repaint();
        }
    }

    public void keyReleased(KeyEvent e) {
        ninja.keyReleased(e);
        repaint();

        startTime = 0;
    }
}

【讨论】:

  • 您确实意识到它们在第一个 keyPressed 和第二个(以及重复的键事件)之间的延迟是不同的并且是特定于操作系统的......
  • 对不起,我没听懂。请你详细解释一下。
  • 第一个 keyPressed 事件和第二个事件之间的时间比第二个和后续 keyPressed 事件的时间长,因此是不均匀的。关键事件之间的时间也因操作系统而异。
  • 谢谢,我现在知道了。但问题在于长时间按住右键并在旋转基础上以一定间隔显示两个图像。这是repaint() 之间的时间,与关键事件无关。这就是为什么它可以在任何操作系统上正常工作的原因。
  • 这可能会导致 Intial 击键之间的更新不均匀。根据您的示例,OP 还需要非常大的 if-else 语句序列
猜你喜欢
  • 2012-02-11
  • 1970-01-01
  • 2013-11-12
  • 2016-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-18
  • 1970-01-01
相关资源
最近更新 更多