简体   繁体   English

Java中的键侦听器/键绑定

[英]Key listeners/key bindings in Java

How do I code an event that starts when a key (specifically the space bar) is pressed, continues running when the key is held , and only stops when the key is released? 我如何代码时,按下一个键(特别是空格键)启动,继续运行时, 按住该键,只有松开按键时停止的事件? I'm trying to simulate a wheeled object that moves across a rough surface. 我正在尝试模拟在粗糙表面上移动的带轮对象。 I've tried using the original KeyListener methods but the problem is, when I hold the space bar the object I'm simulating repeatedly stops and starts. 我尝试使用原始的KeyListener方法,但是问题是,当我按住空格键时,要模拟的对象反复停止并启动。 I've heard a possible solution is key bindings but I still don't understand them even after reading the Java tutorial about it. 我听说可能的解决方案是键绑定,但是即使阅读了有关它的Java教程,我仍然不理解它们。

Here's the paint method used for the simulation (controlled by a Thread which sleeps every 10 milliseconds): 这是用于仿真的绘画方法(由每10毫秒休眠的线程控制一次):

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

And here's the methods used to change x_pos (variables not declared are assumed to have been declared in the class body): 这是用于更改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;      
    }
}   

This was my initial idea for the event: 这是我最初的想法:

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

} }

One of the best and most common approaches is to have a flag for each mapped key. 最好和最常见的方法之一是为每个映射的键都有一个标志。 When it is pressed (detected by a KeyEvent), the flag is set to true. 当按下它(由KeyEvent检测)时,该标志设置为true。 When it is released (also detected by a KeyEvent), the flag is set to false. 当释放它时(也被KeyEvent检测到),该标志设置为false。

The application states (periodically checked by another thread) would be determined not by the Key state or event, but by the flag state. 应用程序状态(由另一个线程定期检查)不是由Key状态或事件决定,而是由标志状态决定。

This simple approach avoids the implications that are caused by key repetition setups. 这种简单的方法避免了由密钥重复设置引起的影响。

I would be the first to argue that sometimes a KeyListener is good thing, but I don't think this is one of them. 我将第一个争辩说有时KeyListener是一件好事,但是我不认为这是其中之一。

Basically, this demonstrates how it might be possible to use Key Bindings to monitor the state change of a key (in this the space bar). 基本上,这演示了如何使用键绑定来监视键的状态变化(在此是空格键)。

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

}

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

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