1

キー (具体的にはスペースバー) が押されたときに開始し、キーを押したままにしておくと実行を継続し、キーを離したときにのみ停止するイベントをコーディングするにはどうすればよいですか? 粗い表面を移動する車輪付きのオブジェクトをシミュレートしようとしています。元の KeyListener メソッドを使用してみましたが、問題は、スペース バーを押したままにすると、シミュレートしているオブジェクトが繰り返し停止して開始することです。可能な解決策はキーバインディングだと聞いたことがありますが、それについての Java チュートリアルを読んでもまだ理解できません。

シミュレーションに使用されるペイント メソッドは次のとおりです (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();
}

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

}

4

2 に答える 2

4

最良かつ最も一般的なアプローチの1つは、マップされたキーごとにフラグを設定することです。押されると(KeyEventによって検出される)、フラグはtrueに設定されます。解放されると(KeyEventによっても検出されます)、フラグはfalseに設定されます。

アプリケーションの状態(別のスレッドによって定期的にチェックされる)は、キーの状態やイベントではなく、フラグの状態によって決定されます。

この単純なアプローチは、キーの繰り返し設定によって引き起こされる影響を回避します。

于 2013-02-28T20:38:50.400 に答える
2

私は時々aが良いことだと最初に主張するでしょうが、KeyListenerこれはそれらの1つではないと思います。

基本的に、これは、キーバインディングを使用してキーの状態変化を監視する方法を示しています(このスペースバー)。

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

}
于 2013-02-28T22:33:55.557 に答える