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

时间:2014-03-30 19:12:34

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

}
}

3 个答案:

答案 0 :(得分:3)

按住该键时,操作系统将为中风生成重复事件。

通常情况下,您需要某种标志,表明keyPressed事件已被处理过。

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

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

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

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

作为一般性建议,您应该使用Key Bindings代替KeyListener,因为它可以让您更好地控制触发关键事件的焦点水平

更新了Key Bindings示例

这取决于您的代码似乎在做什么......

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,它总是在滴答作响,它更新了视图。然后视图将使用模型检查应该更新和呈现的内容以及键绑定将更新模型的状态,但这只是我。

答案 1 :(得分:0)

按住某个键时,keyPressed事件将快速连续发生。你所做的是为这一系列事件增加了5秒的延迟。

解决这个问题取决于你想做什么。如果您只想让事件每5秒发生一次,您可以将计时器移出事件,然后在调用事件时,根据计时器每隔5秒切换一次布尔值,检查是否已经过了5秒。 / p>

答案 2 :(得分:0)

这将解决您的问题。

  

无需计时器

     

它简单地用于系统当前时序......

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