问题
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. 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();
}
回答1:

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. This means that any changes to the UI must go through this central loop.
This example just uses Swing, but the concept should be easy to translate.
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();
}
}
}
回答2:
Written in pseudo code you can build a solution using several parts:
- Introduce a field
saveMessageIsVisible
which is set tofalse
- 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) - also start a timer with 2 seconds duration after which you set the field to false again.
- Inside the paint routine check for the field and draw your save box.
回答3:
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();
}
来源:https://stackoverflow.com/questions/17562252/use-a-timer-when-a-key-is-pressed