2015-05-27 41 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