2014-03-13 247 views
1

可以使用你的帮助作业,包括摆动定时器,动作监听器和多个对象。我不知道是否张贴的问题在这里允许的,但我在使用动画麻烦,这里是我迄今为止Java定时器动作监听器

创建一个具有两个双域x和y一类颗粒, 构造将这些字段初始化为0 和500之间的随机值,返回它们的值的方法getX和getY以及随机将x和y的值 中的值加1或减1的方法void move()。 (添加到x和y的数量是两个单独的随机数 。)接下来,创建一个类ParticleFieldWithTimer,它扩展了 JPanel。这个类应该更喜欢500 * 500像素的大小。它的 构造函数应该首先用100个粒子对象填充一个ArrayList字段,然后启动一个Swing Timer,该Swing Timer的滴答时间为 秒的25倍。在每次打勾时,动作侦听器应首先为每个粒子调用方法 移动,然后调用重绘。 ParticleFieldWithTimer的paintComponent 方法应将每个粒子绘制为其当前坐标的3 * 3 矩形。确保定时器将当用户关闭框架

这是ParticleFieldWithTimer类

import java.awt.Dimension; 
import java.awt.FlowLayout; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.WindowAdapter; 
import java.awt.event.WindowEvent; 
import java.util.ArrayList; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.Timer; 


public class ParticleFieldWithTimer extends JPanel{ 
    private ArrayList<Particle> particle = new ArrayList<Particle>(); 
    Timer timer; 
    boolean b; 
    public ParticleFieldWithTimer(){ 
     this.setPreferredSize(new Dimension(500,500)); 


    for(int i = 0; i < 100; i++) { 
     particle.add(new Particle()); 
     timer = new Timer(40, new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent ae) { 
       // change polygon data 
       // ... 
       Particle p = new Particle(); 
       p.move(); 
       repaint(); 

      } 
     }); 


    } 





} 
    public void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     Graphics2D g2 = (Graphics2D)g; 
     for (Particle p: particle) { 

     double temp1 = p.getX(); 
     double temp2 = p.getX(); 
     int tempX = (int) temp1; 
     int tempY = (int) temp2; 
     g2.fillRect(tempX, tempY, 3, 3); 
     } 




    } 
    public static void main(String[] args) { 
     final JFrame f = new JFrame("ParticleField"); 
     final ParticleFieldWithTimer bb = new ParticleFieldWithTimer(); 
     f.setLayout(new FlowLayout()); 
     f.add(bb); 
     f.addWindowListener(new WindowAdapter() { 
      public void windowClosing(WindowEvent we) { 
       try { 
        bb.finalize(); 
       } catch (Throwable e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
       f.dispose(); 
      } 
     }); 
     f.pack(); 
     f.setVisible(true); 
    } 
} 

这是粒子类

import java.util.Random; 


public class Particle { 
private double x , y ; 

Random r = new Random(); 
public Particle() { 

    x = r.nextDouble()*500; 
    y = r.nextDouble()*500; 

} 
public Double getX() { 
    return x; 
} 
public Double getY() { 
    return y; 
} 
public void move() { 

    x = r.nextInt(2) - 1; 
    y = r.nextInt(2) - 1; 
    System.out.println(x + " " + y); 
} 

}

+0

*“我不知道是否发布问题..”* DYM作业规范?你的问题是什么? –

回答

4

这 停止...

for(int i = 0; i < 100; i++) { 
    particle.add(new Particle()); 
    timer = new Timer(40, new ActionListener() { 
     @Override 
     public void actionPerformed(ActionEvent ae) { 
      // change polygon data 
      // ... 
      Particle p = new Particle(); 
      p.move(); 
      repaint(); 

     } 
    }); 
} 

是错误的方法,它会创建一个100 Timer s,这会影响系统的性能。

您还创建计时器滴答新Particle每一次,这是不是你真正想做的事情要么,你要影响你已经创建了Particle小号...

相反,创建粒子...

for(int i = 0; i < 100; i++) { 
    particle.add(new Particle()); 
} 

然后创建Timer并在其中,通过你已经创建粒子迭代...

timer = new Timer(40, new ActionListener() { 
    @Override 
    public void actionPerformed(ActionEvent ae) { 
     for (Particle p : particle) { 
      p.move(); 
     } 
     repaint(); 
    } 
}); 

不要忘了启动定时器...

timer.start(); 

或改变Graphics背景下,这可能是仍设置为面板的背景颜色...

Graphics2D g2 = (Graphics2D) g; 
g2.setColor(Color.RED); 
for (Particle p : particle) { 

我也注意到...

x = r.nextInt(2) - 1; 
y = r.nextInt(2) - 1; 

是不是在做你想做的。它将始终使值在-1和1之间。相反,您想要将结果添加到x/y值中。

x += r.nextInt(2) - 1; 
y += r.nextInt(2) - 1; 

现在,这种由值 “拖” 对面的(主要)统一的方式在屏幕的...

你可以尝试使用...

x += r.nextBoolean() ? 1 : - 1; 
y += r.nextBoolean() ? 1 : - 1; 

但这最终导致他们在原地跳舞(主要是)...

+0

嗨,谢谢你的回复。不应该重绘在for循环中,我应该对paintcomponent进行哪些修改? – user3363135

+0

不,你想更新整个模型,然后做一个'repaint'。它实际上不会产生很大的差异,因为“RepaintManager”可以将重复调用重新组合为“repaint”成为单个绘画事件,但为什么要冒这个风险。一步更新模型,更新下一个视图。因为'actionPerformed'在EDT的上下文中执行,调用'repaint'只有在'actionPerformed'方法退出之后才会起作用(在存在'actionPerformed'之前不能调用'paintComponent') – MadProgrammer

+0

谢谢解释,这很有道理。然而,我的程序似乎仍然有些问题,在paintcomponent我猜我不应该有一个for循环,但我很困惑,我该怎么办 – user3363135