简体   繁体   English

按下键时使用计时器

[英]Use a timer when a key is pressed

The past week of searching has not brought up any working help for trying to figure out how to do this. 过去一周的搜索没有提供任何有用的帮助,试图找出如何做到这一点。 When a user presses the backspace, it saves the game. 当用户按下退格键时,它会保存游戏。 I set it up that it shows a little box at the top that says "Saving.." and I want that to stay up there for about 2 seconds. 我设置它在顶部显示一个小盒子,上面写着“拯救......”,我想让它在那里停留大约2秒钟。 I can get it to show up while the button is being pressed with this code: 使用此代码按下按钮时,我可以显示它:

if (key.save) {
    font = new Font(null, 0, 16);
    g.setFont(font);
    g.setColor(Color.DARK_GRAY);
    g.fillRect(getWidth() / 2 - 40, -1, 80, 35);
    g.setColor(Color.BLACK);
    g.drawRect(getWidth() / 2 - 40, -1, 80, 35);
    g.setColor(Color.white);
    g.drawString("Saving..", getWidth() / 2 - 30, 22);
}

But this code won't work, it won't even display the box at the top: 但是这段代码不起作用,甚至不会在顶部显示框:

if (key.save) {
    ActionListener action = new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            Font font = new Font(null, 0, 16);
            g.setFont(font);
            g.setColor(Color.DARK_GRAY);
            g.fillRect(getWidth() / 2 - 40, -1, 80, 35);
            g.setColor(Color.BLACK);
            g.drawRect(getWidth() / 2 - 40, -1, 80, 35);
            g.setColor(Color.white);
            g.drawString("Saving..", getWidth() / 2 - 30, 22);
        }
    };

    timer = new Timer(0, action);
    timer.start();
}

在此输入图像描述

This is an example of the basic concept of using a list of renderable artifacts which can be updated over time. 这是使用可以随时间更新的可渲染工件列表的基本概念的示例。

The basic idea is there is a central paint loop that is responsible for updating the current state of the UI based on what you want to render. 基本思想是有一个中央绘制循环,负责根据您想要渲染的内容更新UI的当前状态。 This means that any changes to the UI must go through this central loop. 这意味着对UI的任何更改都必须通过此中央循环。

This example just uses Swing, but the concept should be easy to translate. 这个例子只使用Swing,但这个概念应该很容易翻译。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class QuickPaint01 {

    public static void main(String[] args) {
        new QuickPaint01();
    }

    public QuickPaint01() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel implements Environment {

        private List<Drawable> drawables;

        public TestPane() {
            drawables = new ArrayList<>(25);
            Timer update = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Drawable[] draws = drawables.toArray(new Drawable[drawables.size()]);
                    for (Drawable drawable : draws) {
                        if (drawable instanceof Moveable) {
                            ((Moveable)drawable).update(TestPane.this);
                        }
                    }
                    repaint();
                }
            });
            update.setCoalesce(true);
            update.setRepeats(true);
            update.start();
            drawables.add(new Ball());
        }

        @Override
        public void add(Drawable drawable) {
            drawables.add(drawable);
        }

        @Override
        public void remove(Drawable drawable) {
            drawables.remove(drawable);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            for (Drawable drawable : drawables) {
                drawable.draw(this, g2d);
            }
            g2d.dispose();
        }
    }

    public interface Environment {

        public Dimension getSize();
        public void add(Drawable drawable);
        public void remove(Drawable drawable);

    }

    public interface Drawable {

        public void draw(Environment env, Graphics2D g);

    }

    public interface Moveable extends Drawable {

        public void update(Environment env);

    }

    public class Ball implements Moveable {

        private int radius = 20;

        private int x = 0;
        private int y = 0;

        private int xDelta = 4;

        private Shape shape;

        public Ball() {
            shape = new Ellipse2D.Float(0, 0, radius, radius);
        }

        @Override
        public void update(Environment env) {
            x += xDelta;
            if (x + radius > env.getSize().width) {

                x = env.getSize().width - radius;
                xDelta *= -1;

                env.add(new Message(env, "<< Bounce", 1));

            } else if (x < 0) {

                x = 0;
                xDelta *= -1;

                env.add(new Message(env, "Bounce >> ", 1));

            }
            y = (env.getSize().height - radius) / 2;
        }

        @Override
        public void draw(Environment env, Graphics2D g) {
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.translate(x, y);
            g2d.setColor(Color.BLUE);
            g2d.fill(shape);
            g2d.dispose();
        }

    }

    public class Message implements Drawable {

        private Environment environment;
        private String message;
        private int delay;

        public Message(Environment environment, String message, int delay) {
            this.environment = environment;
            this.message = message;
            this.delay = delay;

            Timer timer = new Timer(delay * 1000, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Message.this.environment.remove(Message.this);
                }
            });
            timer.start();
        }

        @Override
        public void draw(Environment env, Graphics2D g) {
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(Color.RED);
            FontMetrics fm = g2d.getFontMetrics();
            g2d.drawString(message, env.getSize().width - fm.stringWidth(message), 0 + fm.getAscent());
            g2d.dispose();
        }

    }

}

Written in pseudo code you can build a solution using several parts: 用伪代码编写,您可以使用几个部分构建解决方案:

  • Introduce a field saveMessageIsVisible which is set to false 引入一个设置为false的字段saveMessageIsVisible
  • Inside the key handling method 内部的密钥处理方法
    • clone the game state 克隆游戏状态
    • start a new thread and save the state 启动一个新线程并保存状态
    • at the end of this thread, set saveMessageIsVisible to true (and optionally perform invalidate screen) 在此线程的末尾,将saveMessageIsVisible设置为true(并可选择执行invalidate屏幕)
    • also start a timer with 2 seconds duration after which you set the field to false again. 还会启动一个持续时间为2秒的计时器,然后再将该字段设置为false。
  • Inside the paint routine check for the field and draw your save box. 在绘图例程内检查字段并绘制保存框。

for perform a task for a given period of time, you could do the following: 要在给定的时间段内执行任务,您可以执行以下操作:

ExecutorService service = Executors.newSingleThreadExecutor();
try {
    Runnable r = new Runnable() {
       @Override
       public void run() {
         // task
       }
    };

    Future<?> f = service.submit(r);

    f.get(2, TimeUnit.MINUTES);     // attempt the task for two minutes
} catch (Exception e) {
     //Handele Exception
} finally {
     service.shutdown();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM