2013-02-28 140 views
1

如何編碼當按鍵(特別是空格鍵)被按下時啓動的事件,在鍵被保持爲時繼續運行,並且僅在釋放鍵時停止?我試圖模擬在粗糙表面上移動的輪式物體。我試過使用原始的KeyListener方法,但問題是,當我持有空格鍵時,我模擬的對象反覆停止並開始。我聽說一個可能的解決方案是關鍵綁定,但即使閱讀了關於它的Java教程,我仍然不理解它們。Java中的鍵監聽器/鍵綁定

下面是用於模擬(由休眠每隔10毫秒的線程控制)paint方法:

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

可以有更多的方法來做到這一點。我過去處理這個問題的方式將是一個監控系統,因此我會在任何時候檢查密鑰是否關閉。當動畫/效果是時間的函數時,效果很好。 – 2013-02-28 20:36:40

回答

4

其中最好和最常見的方法是爲每個映射的鍵設置一個標誌。當它被按下時(由KeyEvent檢測到),該標誌被設置爲真。當它被釋放(也被KeyEvent檢測到)時,該標誌被設置爲false。

應用程序狀態(由另一個線程週期性地檢查)將不由鍵狀態或事件確定,而是由標誌狀態確定。

這種簡單的方法避免了由重複重複設置造成的影響。

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

} 
+0

+1個很好的例子... – 2013-03-01 08:34:53