2014-11-09 3 views
-2

버튼을 누를 때마다 직사각형을 움직이는 코드 조각이 있습니다. 키를 누를 때마다 x 또는 y 좌표가 1 픽셀 씩 감소하거나 증가하도록 설정됩니다. 그러나, 만약 내가 같은 키를 두 번 이상 누르면, 그 자체로 어떻게 든 하나의 픽셀이 합성되고, 스택이 더 좋은 단어가 될 수 있고 기하 급수적으로 증가한다는 것을 알게되었습니다. 코드에서 왜이 작업을 수행하는지 알 수있는 내용이 있습니까?왜 내 변수가 기하 급수적으로 증가합니까?

public void paintComponent(Graphics g){ 
    //.. 
    addKeyListener(this); // adds another KeyListener 
} 

을 그리고 keyPressed가 호출 될 경우 repaint();의 모든 호출은 자신의 일을 할 것입니다 다른 KeyListener을 추가

public class drawingComponent extends JComponent implements KeyListener 
{ 

    Rectangle hello = new Rectangle(300, 100, 50, 50); 

    public void paintComponent (Graphics g) 
    { 
     Graphics2D g2 = (Graphics2D)g; 
     g2.setColor(new Color(255, 25, 0)); 
     g2.setFont(new Font("monospace", Font.BOLD + Font.ITALIC, 30)); 
     g2.drawString("nothing yet", 300, 320); 
     g2.fill(hello); 
     setFocusable(true); 
     requestFocus(); 
     addKeyListener(this); 

    } 

    @Override 
    public void keyPressed (KeyEvent e) 
    { 

     if (e.getKeyCode() == KeyEvent.VK_W) 
     { 
      hello.y = hello.y - 1; 
      hello.setLocation(hello.x, hello.y); 
      repaint(); 
      System.out.println(hello.y); 
     } 
     if (e.getKeyCode() == KeyEvent.VK_S) 
     { 
      hello.y = hello.y + 1; 
      hello.setLocation(hello.x, hello.y); 
      repaint(); 

     } 
     if (e.getKeyCode() == KeyEvent.VK_A) 
     { 
      hello.x = hello.x - 1; 
      hello.setLocation(hello.x, hello.y); 
      repaint(); 

     } 
     if (e.getKeyCode() == KeyEvent.VK_D) 
     { 
      hello.x = hello.x + 1; 
      hello.setLocation(hello.x, hello.y); 
      repaint(); 

     } 

    } 

    @Override 
    public void keyReleased (KeyEvent e) 
    { 

    } 

    @Override 
    public void keyTyped (KeyEvent e) 
    { 
     // TODO Auto-generated method stub 

    } 
} 
+1

하여 들여 쓰기를 수정하신 후 How to Use Key Bindings보기 ... 필요하지 않습니다. –

+7

"지수"는 "빨리"와 동의어가 아닙니다. – khelwood

+2

고양이/개가 키보드를 통과하도록하여 코드를 포맷 했습니까? 가능한 코드를 모호하게 만드는 노력은 분명하지만 더 일반적인 형식 기술을 사용하는 것이 좋습니다. –

답변

13

당신은 당신의 구성 요소의 각 다시 그리기에 KeyListener를 추가하고 있습니다. 즉, 먼저 one 청취자가 있고 two 다음에 four, 그 다음 sixteen 등의 의미입니다.

하지 마십시오. 생성자에서 한 번 리스너를 추가하십시오.

생성자는 다음과 같이 할 수 있습니다 : 당신은 또는 다른 시스템이나 플랫폼에서 작동하지 않을 수 있습니다 해킹 및 해결 방법을 사용하여 API와 고유의 문제를 극복하기 위해 노력하고있다

public drawingComponent() { 
    // init other stuff 
    addKeyListener(this); 
} 
+2

아니면 그냥 키를 사용하십시오. 대신 바인딩 : P – MadProgrammer

+1

+1하지만 @MadProgrammer 동의합니다 (그의 답변 +1). Key Bindings는 [이 주제에 대한 이전 기사]에서 논의 된 바와 같이이 상황에서 훨씬 더 나은 해결책입니다 (http://stackoverflow.com/questions/26831196/request-focus-for-keylistener-not-sure-if-i). -have-focus-or-not). –

4

.

paint 메서드 내에서 구성 요소의 상태를 변경하지 말고, 페인팅은 현재 상태를 그려야합니다. 페인트 메서드 내에서 포커스를 요청하면 다른 다시 칠하기 요청이 트리거되어 CPU주기를 소모하는 악순환이 발생할 수 있습니다.

핵심 문제는 (톰이 강조한대로) paint이 호출 될 때마다 다른 KeyListener을 추가하는 것입니다. 회화는 많은 일이 발생할 것이며, 일반적으로 당신의 지식이나 요청이없는 것입니다.

이 문제를 해결하는 대신 키 바인딩 API를 수정하도록 고안된 API를 사용해야합니다. 이 API를 사용하면 키 이벤트를 트리거하는 데 필요한 포커스 수준을 정의 할 수 있습니다. 다음 예는 KeyListener의 기본 동작을 모방합니다 (다른 요구 사항을 모르므로).하지만 구성 요소가 집중력.

몇 가지 팁 ...

  • 항상 발신자 super.paintComponent 커스텀 페인팅을하기 전에,이 잊지 일부 심각하게 이상한 그래픽 결함이 발생할 수 있습니다 쉽습니다.
  • paintComponentpublic 일 필요가 없습니다. 아무도 전화를 걸지 않으실 겁니다. 당신은 Code Conventions for the Java TM Programming Language을 통해 읽기를하는 것 같아서
  • , 그것은 ... 쉽게 다른 사람
  • 간단한 예를 들어

을 읽는 사람들이 코드를 읽을과 있도록합니다

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Font; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Rectangle; 
import java.awt.event.ActionEvent; 
import java.awt.event.KeyEvent; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import javax.swing.AbstractAction; 
import javax.swing.ActionMap; 
import javax.swing.InputMap; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.KeyStroke; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class Test { 

    public static void main(String[] args) { 
     new Test(); 
    } 

    public Test() { 
     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 DrawingComponent()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class DrawingComponent extends JComponent { 

     Rectangle hello = new Rectangle(300, 100, 50, 50); 

     public DrawingComponent() { 
      setFocusable(true); 
      InputMap im = getInputMap(); 

      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "Move.up"); 
      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), "Move.down"); 
      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "Move.left"); 
      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "Move.right"); 

      ActionMap am = getActionMap(); 
      am.put("Move.up", new DeltaAction(0, -1)); 
      am.put("Move.down", new DeltaAction(0, 1)); 
      am.put("Move.left", new DeltaAction(-1, 0)); 
      am.put("Move.right", new DeltaAction(1, 0)); 

      addMouseListener(new MouseAdapter() { 
       @Override 
       public void mouseClicked(MouseEvent e) { 
        requestFocusInWindow(); 
       } 
      }); 
     } 

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

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2 = (Graphics2D) g; 
      g2.setColor(new Color(255, 25, 0)); 
      g2.setFont(new Font("monospace", Font.BOLD + Font.ITALIC, 30)); 
      g2.drawString("nothing yet", 300, 320); 
      g2.fill(hello); 
     } 

     public class DeltaAction extends AbstractAction { 

      private int xDelta; 
      private int yDelta; 

      public DeltaAction(int xDelta, int yDelta) { 
       this.xDelta = xDelta; 
       this.yDelta = yDelta; 
      } 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       hello.x += xDelta; 
       hello.y += yDelta; 
       repaint(); 
      } 

     } 

    } 

} 

"그렇다면 키 바인딩 API를 사용해야하는 이유는 무엇입니까?" 묻는 다면요?이벤트를 트리거하는 데 필요한 포커스 레벨 설정을 포함하여 더 많은 유연성과 구성 가능성을 제공하는 것 외에도 이벤트를보다 쉽게 ​​트리거하는 키를 변경하거나 여러 키 세트를 가질 수 있습니다 (화살표 키도 생각할 수 있음). 버튼을 포함하여 Swing API의 다른 부분과 함께 사용할 수 있습니다.

단일 Action

JMenuItem의, JButton의 키 바인딩에 적용 할 수있는, 불필요한 코딩

은 자세한 내용

+1

상세하고 전문적인 답변을 주셔서 감사합니다. – wilkers

관련 문제