如何对按键(特别是空格键)时启动的事件进行编码,当键保持时继续运行,并且仅在释放键时停止?我试图模拟一个在粗糙表面上移动的轮式物体。我尝试过使用原始的KeyListener方法,但问题是,当我按住空格键时,我正在反复模拟的对象会停止并启动。我听说过一个可能的解决方案是关键绑定,但即使在阅读了Java教程之后我仍然不理解它们。
这是用于模拟的绘制方法(由每10毫秒休眠一次的Thread控制):
public void paint(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Shape roadsurface = new Rectangle2D.Float(0, 85, 1000, 200);
g2.setColor(Color.BLACK);
g2.setStroke(new BasicStroke(10));
g2.draw(roadsurface);
g2.setColor(new Color(102, 102, 153));
g2.fill(roadsurface);
Image carimage = Toolkit.getDefaultToolkit().getImage("cargrey.png");
g2.drawImage(carimage, x_pos, y_pos, 60, 30, this);
g2.finalize();
}
以下是用于更改x_pos的方法(未声明的变量假定已在类主体中声明):
public void accelerate()
{
do
{ acc = 15.0 - t;
vel = ( t * 15.0) - ( 0.5 * Math.pow(t, 2.0) );
disp = ( 0.5 * 15.0 * Math.pow(t, 2.0) ) - ( (1.0/6.0) * Math.pow(t, 3.0) );
x_pos = (int)disp;
t += 0.01; break;} while (acc > 0);
while (acc <= 0)
{ acc = 0;
disp = t * vel;
x_pos = (int)disp;
t += 0.01;
}
}
public void brake(double vel, double disp)
{
double u = 0;
double disp2;
while (vel > 0)
{
disp2 = (vel * u) + (0.5 * -100 * Math.pow(u, 2.0) );
vel = vel + (-100 * u);
x_pos = (int)(disp + disp2);
u += 0.01;
t += 0.01; break;}
while (vel <= 0)
{
u += 0.01;
t += 0.01;
}
}
这是我对这次活动的最初想法:
class Key1 extends Thread implements KeyListener
{
Track g;
boolean keyIsPressed;
Key1(Track g)
{
this.g = g;
}
public void keyTyped(KeyEvent ke) {}
public void keyPressed(KeyEvent ke)
{
if (ke.getKeyCode() == KeyEvent.VK_SPACE)
keyIsPressed = true;
}
public void keyReleased(KeyEvent ke)
{
if (ke.getKeyCode() == KeyEvent.VK_SPACE)
keyIsPressed = false;
}
public void run()
{
while (keyIsPressed)
{
g.repaint();
g.accelerate();
try
{
Thread.sleep(10);
}
catch (InterruptedException ex)
{
// swallowed
}
while (!keyIsPressed)
{
g.repaint();
g.brake(g.vel, g.disp);
try
{
Thread.sleep(10);
}
catch (InterruptedException ex)
{
// swallowed
}
}
}
答案 0 :(得分:4)
最好和最常见的方法之一是为每个映射键设置一个标志。按下它(由KeyEvent检测)时,该标志设置为true。当它被释放时(也被KeyEvent检测到),该标志被设置为false。
应用程序状态(由另一个线程定期检查)不是由Key状态或事件确定的,而是由标志状态确定的。
这种简单的方法避免了由密钥重复设置引起的影响。
答案 1 :(得分:2)
我会第一个认为有时KeyListener
是好事,但我不认为这是其中之一。
基本上,这演示了如何使用键绑定来监视键的状态变化(在空格键中)。
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
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.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class KeyBindingTest {
public static void main(String[] args) {
new KeyBindingTest();
}
public KeyBindingTest() {
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 {
private boolean spaceIsDown = false;
public TestPane() {
// Avoid all the issues with focusable and single
// focused components
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false), "space.pressed");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true), "space.released");
am.put("space.pressed", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
spaceIsDown = true;
repaint();
}
});
am.put("space.released", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
spaceIsDown = false;
repaint();
}
});
}
public boolean isSpaceIsDown() {
return spaceIsDown;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
String text = isSpaceIsDown() ? "Space is DOWN" : "Space is UP";
FontMetrics fm = g2d.getFontMetrics();
g2d.drawString(text, (getWidth() - fm.stringWidth(text)) / 2, (((getHeight() - fm.getHeight())) / 2) + fm.getAscent());
g2d.dispose();
}
}
}