2015-05-27 42 views
1

我一直在試圖找出如何使用箭頭鍵移動矩形,但似乎存在問題。
我正在使用KeyListener來檢測所有關鍵輸入。
我不知道如何使用KeyBinding,因此我不希望解決方案擁有它。
我打算在掌握KeyListener之後學習它。請給我建議如何解決它。如何在java中使用鍵移動矩形

package expo; 

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Rectangle; 
import java.awt.event.KeyEvent; 
import java.awt.event.KeyListener; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 

public class Expo extends JPanel implements KeyListener{ 
    int x = 0; 
    int y = 0; 

    @Override 
    public void keyTyped(KeyEvent e) { 
     //System.out.println("Key Typed"); 
    } 

    @Override 
    public void keyPressed(KeyEvent e) { 

     if(e.getKeyCode() == KeyEvent.VK_DOWN){ 
      System.out.println("Key Pressed" + e.getKeyCode()); 
      y = y + 2;  
     } 
    } 

    @Override 
    public void keyReleased(KeyEvent e) { 
     //System.out.println("Key Released"); 
    } 

    public void paint(Graphics g){ 
     g.setColor(Color.BLUE); 
     g.drawRect(x ,y,100,100); 

     repaint(); 
    } 

    public static void main(String[] args) throws InterruptedException { 

     Expo expo = new Expo(); 
     JFrame f = new JFrame(); 

     f.setVisible(true); 
     f.setSize(500,500); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.addKeyListener(expo); 

     f.add(expo); 
     f.repaint();   
    } 
} 
+0

1)覆蓋'paintComponent' ,而不是'paint' 2)不要在paint(或paintComponent)中調用'repaint' 3)如果你想在'KeyListener.keyPressed'被觸發後重新繪製,然後調用repaint。 4)如果KeyListener未觸發,請確保包含偵聽器的組件在焦點 – copeg

+0

在矩形重畫時重繪,它在原始焦點上重繪 – yj2000

+0

也嘗試了paintcomponent,但不會顯示矩形 – yj2000

回答

0

只要改變這兩段代碼:

@Override 
public void keyPressed(KeyEvent e) { 

    if(e.getKeyCode() == KeyEvent.VK_DOWN){ 
     System.out.println("Key Pressed" + e.getKeyCode()); 
     y = y + 2; 

     repaint();//add this line to update the UI 
    } 
} 

public void paint(Graphics g){ 
    super.paint(g);//you should always call the super-method first 

    g.setColor(Color.BLUE); 
    g.drawRect(x ,y,100,100); 
} 

這將解決這個問題。雖然我建議覆蓋paintComponent而不是paint(請閱讀本文中有關「油漆方法」一節:Painting in AWT and Swing)。基本上這些變化都是我作出的改變如下:
keyPressed這一行:repaint();會在廣場移動後更新UI。實際上廣場之前也被移動了,但是直到UI更新之後,這些變化纔會顯示出來。在paint這一行:super.paint(g);使面板首先執行它的默認繪製,其中包括清除整個面板。我已經刪除了repaint();電話,因爲它完全沒用。

注: 如果使用paintComponent而不是paint,你必須第一個電話改變從super.paint(g)super.paintComponent(g)避免計算器。

+0

非常感謝你! – yj2000

1
  1. 使用密鑰綁定API而不是KeyListener,它解決了KeyListener遭受的焦點相關問題。 How to Use Key Bindings
  2. 不要破壞塗料鏈。如果您重寫paint方法之一,則必須將其稱爲super實現。
  3. 避免重寫paint,它通常在繪畫過程中很高,並且由於繪畫工作的方式,在繪製子組件時並不總是被調用,這可能會導致一些有趣的問題。公約建議改用paintComponent。見Painting in AWT and SwingPerforming Custom Painting更多細節
  4. 嘗試調用JFrame#setVisible最後,你已經建立了UI之後,你會發現它會導致更少的問題

舉個例子...

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.event.ActionEvent; 
import java.awt.event.KeyEvent; 
import javax.swing.AbstractAction; 
import javax.swing.Action; 
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 Expo extends JPanel { 

    int x = 0; 
    int y = 0; 

    public Expo() { 
     bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), new AbstractAction() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       y += 2; 
       if (y + 100 > getHeight()) { 
        y = getHeight() - 100; 
       } 
       repaint(); 
      } 
     }); 
     bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), new AbstractAction() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       y -= 2; 
       if (y < 0) { 
        y = 0; 
       } 
       repaint(); 
      } 
     }); 
    } 

    public void bindKeyStrokeTo(int condition, String name, KeyStroke keyStroke, Action action) { 
     InputMap im = getInputMap(condition); 
     ActionMap am = getActionMap(); 

     im.put(keyStroke, name); 
     am.put(name, action); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     g.setColor(Color.BLUE); 
     g.drawRect(x, y, 100, 100); 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(500, 500); 
    } 

    public static void main(String[] args) throws InterruptedException { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
        ex.printStackTrace(); 
       } 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(new Expo()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

} 

這一切酷酷的一切,但現在,當你按下鍵時,矩形移動,暫停,然後開始穩步移動!?

這實際上很正常。相反,你可以做的是建立一個「更新循環」,它不斷監視一組標誌的狀態,決定在設置這些標誌並更新UI時該怎麼做。

那麼,這是什麼呢,是建立一個Swing Timer其中蜱每40毫秒,檢查當前的「垂直化國家重點」的狀態,相應地更新y位置與日程安排repaint,這使得一個更因爲我們不依賴於重複擊鍵,所以運動更流暢。

這也表明了鍵綁定API的權力,因爲它建立了一個單一的Action處理上下運動和相關聯的鍵將同時釋放...整齊

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.KeyEvent; 
import javax.swing.AbstractAction; 
import javax.swing.Action; 
import javax.swing.ActionMap; 
import javax.swing.InputMap; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.KeyStroke; 
import javax.swing.Timer; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class Expo extends JPanel { 

    int x = 0; 
    int y = 0; 

    public enum VerticalKey { 

     UP, DOWN, NONE; 
    } 

    public enum HorizontalKey { 

     LEFT, RIGHT, NONE; 
    } 

    private VerticalKey verticalKeyState = VerticalKey.NONE; 
    private HorizontalKey horizontalKeyState = HorizontalKey.NONE; 

    public Expo() { 
     bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "pressed.down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), new VerticalAction(VerticalKey.DOWN)); 
     bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "released.down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), new VerticalAction(VerticalKey.NONE)); 
     bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "pressed.up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), new VerticalAction(VerticalKey.UP)); 
     bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "released.up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), new VerticalAction(VerticalKey.NONE)); 

     Timer timer = new Timer(40, new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       switch (verticalKeyState) { 
        case UP: 
         y -= 2; 
         break; 
        case DOWN: 
         y += 2; 
         break; 
       } 
       if (y + 100 > getHeight()) { 
        y = getHeight() - 100; 
       } else if (y < 0) { 
        y = 0; 
       } 

       repaint(); 
      } 
     }); 
     timer.start(); 
    } 

    public void bindKeyStrokeTo(int condition, String name, KeyStroke keyStroke, Action action) { 
     InputMap im = getInputMap(condition); 
     ActionMap am = getActionMap(); 

     im.put(keyStroke, name); 
     am.put(name, action); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     g.setColor(Color.BLUE); 
     g.drawRect(x, y, 100, 100); 
    } 

    public void setVerticalKeyState(VerticalKey verticalKeyState) { 
     this.verticalKeyState = verticalKeyState; 
     System.out.println(verticalKeyState); 
    } 

    public void setHorizontalKeyState(HorizontalKey horizontalKeyState) { 
     this.horizontalKeyState = horizontalKeyState; 
    } 

    public class VerticalAction extends AbstractAction { 

     private VerticalKey verticalKey; 

     public VerticalAction(VerticalKey verticalKeys) { 
      this.verticalKey = verticalKeys; 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      setVerticalKeyState(verticalKey); 
     } 

    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(500, 500); 
    } 

    public static void main(String[] args) throws InterruptedException { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
        ex.printStackTrace(); 
       } 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(new Expo()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

} 
+0

謝謝你們! – yj2000