2013-11-04 5 views
0

안녕하세요 모두 내가 설정 한 ArrayList에 새 공을 추가해야하는 버튼이 있습니다. 새로운 공을 추가하는 대신 공이 이미 빨라졌습니다. 이 버튼을 처리하는 클래스이지만ActionListener를 사용하여 새 요소 추가

import java.awt.*; 
import java.awt.event.*; 
import java.awt.geom.*; 
import javax.swing.*; 

@SuppressWarnings("serial") 
public class CreateCircle extends JPanel { 
/* Ports JFrame width, height from BouncingDrawFrame */ 
static double c, d; 
/* Ports desired size of Circle */ 
static int r = 20; // Initial Value 20 
/* Ports timer delay from BouncingDrawFrame */ 
static int z = 10; // Initial Value 10 
/* Timer to control speed */ 
static Timer t = new Timer(z, null); 
/* X,Y points to start, speed of movement */ 
static double x, y, velX = 1, velY = 1; 
/* Ports color choice from BouncingDrawFrame */ 
static Color myColor; 

public CreateCircle(int a, int b) { 
    /* Height of Frame */ 
    c = a; 
    /* Width of Frame */ 
    d = b; 

    t.start(); 

    t.addActionListener(new ActionListener() { 
     public void actionPerformed(ActionEvent arg0) { 
      /* "Bounces" the Ball off the sides */ 
      if (x < 0 || x > (d - (r + 2))) { 
       velX = -velX; 
      } 
      /* "Bounces" the Ball off the top and bottom */ 
      if (y < 0 || y > (c - (r + 30))) { 
       velY = -velY; 
      } 
      /* Moves ball 2 pixels each timer action */ 
      x += velX; 
      y += velY; 
      repaint(); 
     } 

    }); 
} 

public void paintComponent(Graphics g) { 
    super.paintComponent(g); 
    Graphics2D g2 = (Graphics2D) g; 
    Ellipse2D circle = new Ellipse2D.Double(x, y, r, r); 
    g2.setColor(myColor); 
    g2.fill(circle); 

} 
} 

및 클릭 한 경우 새로운 볼 작성 : 이 CreateCircle 공을 만들어 단지 속도 버튼을 클릭, 새로운 공을 만드는 대신

import java.awt.*; 
import java.awt.event.*; 
import java.util.*; 
import javax.swing.*; 

@SuppressWarnings("serial") 
public class BouncingDrawFrame extends JFrame { 
public BouncingDrawFrame() { 
    /* 
    * Create ArrayList to hold balls, remember ArrayList is not a component 
    * but the elements of ArrayList are 
    */ 
    final ArrayList<CreateCircle> ballList = (ArrayList<CreateCircle>) new ArrayList<CreateCircle>(); 

    /* Create Main Ball Frame */ 
    final JFrame main = new JFrame(); 
    main.setTitle("Bouncing Balls!!"); 
    main.setSize(350, 500); 
    main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    main.setLocationRelativeTo(null); 
    main.setVisible(true); 

    /* Create Control Panel */ 
    JFrame control = new JFrame(); 
    control.setSize(300, 300); 
    control.setTitle("Change Settings!"); 
    control.setLocationRelativeTo(null); 
    control.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    control.setVisible(true); 

    final JPanel p1 = new JPanel(); 
    p1.setLayout(new GridLayout(10, 2)); 
    control.add(p1); 

    final JButton addBall = new JButton("Add A Ball"); 
    p1.add(addBall); 

    /* Y Point */ 
    final int a = main.getHeight(); 
    /* X Point */ 
    final int b = main.getWidth(); 

    ballList.add(new CreateCircle(a, b)); 
    main.add(ballList.get(0)); 

    addBall.addActionListener(new ActionListener() { 
     private int click; 

     public void actionPerformed(ActionEvent arg0) { 
      click++; 
      ballList.add((click), new CreateCircle(a, b)); 
      System.out.println(click); 
      System.out.println(ballList.size()); 
      main.add(ballList.get(click)); 
      repaint(); 
     } 
    }); 
} 
} 

을 첫 번째 공의 움직임. 클릭 수와 동일한 ArrayList의 인덱스에 새로운 공을 추가하려고합니다. 나는 ArrayList 크기가 있고 클릭 수를 시스템에 출력하므로 ArrayList는 클릭 한 횟수와 함께 크기가 증가하고 있음을 알 수 있습니다. 왜 새로운 CreateCircle을 추가하지 않는지 모르겠습니다.

추신 : 여기에 주요 스레드가 있습니다. 당신의 CreateCircle 클래스

public class BouncingRun { 
public static void main(String[] args) { 
    new BouncingDrawFrame(); 
} 
} 
+2

정적 수정자를 많이 사용합니다. ** 편집 ** - 지금 제이슨 C가 답변으로 언급 한 것을 볼 수 있습니다. 그의 대답에 1+. –

답변

4

모든 필드 그들이 CreateCircle의 모든 인스턴스간에 공유되는 것을 의미 static입니다. 본질적으로 이는 볼 중 하나에서 수행하는 모든 계산이 모든 볼에서 발생하며 모든 볼이 동일하다는 것을 의미합니다.

해당 속성을 CreateCircle의 특정 인스턴스와 연관 시키려면 해당 속성을 static으로 설정해야합니다.

http://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html의 인스턴스 및 클래스 멤버에 대한 공식 자습서를 살펴 보시기 바랍니다.

질문에 기반한 업데이트 : flicker below : 나는 당신이 이것을 어떻게 할 수 있는지를 보여주는 JLabel의 튀는 예제 (http://pastebin.com/w1D9H6k2)를 만들었고 Swing이 다시 그리기 등을 처리하도록했습니다. 여기에 또한 있습니다 :

import java.awt.Color; 
import java.awt.Container; 
import java.awt.Dimension; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 

import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.SwingUtilities; 
import javax.swing.Timer; 


@SuppressWarnings("serial") 
public class BouncingLabels extends JFrame { 

    // this is our bouncing label component. it bounces around its parent. this could 
    // be pulled out into its own class file; its in here to keep the example self 
    // contained. 
    static class BouncingLabel extends JLabel { 

     private int fieldWidth, fieldHeight; // width/height of parent at creation time. 
     private int velX = 1, velY = 1; // current x and y velocity. 

     // constructor sets base label properties and starts a timer. 
     public BouncingLabel (int fieldWidth, int fieldHeight) { 

      this.fieldWidth = fieldWidth; 
      this.fieldHeight = fieldHeight; 

      setBounds(0, 0, 60, 20); 
      setOpaque(true); 
      setBackground(Color.RED); 
      setForeground(Color.WHITE); 
      setText("HELLO"); 
      setVisible(true); 

      // timer will call step() every 10ms. 
      new Timer(10, new ActionListener() { 
       @Override public void actionPerformed (ActionEvent e) { 
        step(); 
       } 
      }).start(); 

     } 

     // step updates the component position. note that no explicit painting is done. 
     private void step() { 

      int x = getX(); 
      int y = getY(); 
      int maxx = fieldWidth - getWidth(); 
      int maxy = fieldHeight - getHeight(); 

      x += velX; 
      y += velY; 

      if ((x >= maxx && velX > 0) || (x <= 0 && velX < 0)) 
       velX = -velX; 
      if ((y >= maxy && velY > 0) || (y <= 0 && velY < 0)) 
       velY = -velY; 

      setLocation(x, y); 

     } 

    } 

    // BouncingLabels is our main frame; click on it to add a label. 
    public BouncingLabels() { 

     // work with the content pane, not the frame itself. 
     final Container c = getContentPane(); 
     c.setPreferredSize(new Dimension(300, 300)); 
     c.setLayout(null); 
     setResizable(false); 
     pack(); 

     // add an initial bouncing object. 
     c.add(new BouncingLabel(c.getWidth(), c.getHeight())); 

     // clicking on the frame will add a new object. 
     addMouseListener(new MouseAdapter() { 
      @Override public void mouseClicked (MouseEvent e) { 
       if (e.getButton() == MouseEvent.BUTTON1) 
        c.add(new BouncingLabel(c.getWidth(), c.getHeight())); 
      }    
     }); 

    } 

    // main method creates and shows a BouncingLabels frame. 
    public static void main (String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override public void run() { 
       BouncingLabels b = new BouncingLabels(); 
       b.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       b.setLocationRelativeTo(null); 
       b.setVisible(true); 
      } 
     }); 
    } 

} 

예를 들어, 라벨 대신 공을 사용하려면 예 : JComponent이고 코드는 기본적으로 동일합니다. 단, paint()을 오버라이드하여 Swing에 구성 요소 그리기 방법을 알려 주어야합니다. 즉, paint() 구현에서 볼 위치 나 그와 같은 것에 대해 걱정할 필요가 없습니다. 스윙은 이미 구성 요소의 위치와 크기를 유지합니다. 구성 요소의 좌표계에 원을 그려야합니다.

+0

감사합니다. 고맙습니다. 모든 변수와 필드에서 정적 수정자를 제거했지만, 지금은 새 공을 만들 때 깜박입니다. repaint()를 어디에 둘 필요가 있습니까? – Sam

+1

코드에 많은 문제가 있습니다. 특히'CreateCircle'을 추가 할 때마다 컴포넌트이기 때문에, 그 기하학은 메인 윈도우의 레이아웃 매니저 (main.getContentPane()에 추가해야하는 BTW,'main'이 아니라)에 의해 결정됩니다. 실제로하는 일은 전체 프레임을 차지하고 서로 겹치는 여러 가지 맞춤 구성 요소를 만드는 것입니다. 'JPanel'의 기존 기능을 더 많이 사용하려면 코드를 재 작성해야합니다. 기본 JPanel의 X, Y, 너비 및 높이 속성을 사용하고, 타원을 그리며 null 레이아웃을 사용합니다 매니저. 스윙이 일하게하십시오. –

+0

예제를 추가했습니다. –

관련 문제