I have 100 particles that all move with the help of Timer
and ActionListener
. I'm tracking the movement of my particles by saving the coordinates x,y
in a StringBuilder
. When the process is done I'm trying to print the results into a CSV-file, with an output that looks like this;
time1, x1, y1, x2, y2, ... , xn, yn
time2, x1, y1, x2, y2, ... , xn, yn
, At the moment the timer stops after the particles have moved 100 times, I use a counter in my ActionListener
to get this done. The problem is, my output in my CSV-file looks all messed up with more than 600 rows, it should only have 100 rows.
I've tried using different "newline"-commands like \n
, \r\n
, %n
, but none of them gives me 100 lines.
The reason I want to use a StringBuilder
and not just use +
is because I want the code to work for as many particles as possible. If you have any other suggestions, I would gladly take them.
Controller
:
import javax.swing.event.*;
import java.awt.event.*;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import javax.swing.*;
public class Controller extends JPanel implements ActionListener{
Model model;
View view;
private Timer timer;
private int delta = 100;
private StringBuilder csv = new StringBuilder();
private int counter = 0;
private int time = 2000;
public Controller(Model m, View v) {
model = m;
view = v;
timer = new Timer(delta, this);
timer.setInitialDelay(time);
timer.start();
}
public void actionPerformed(ActionEvent arg0) {
counter++;
csv.append(time);
csv.append(",");
csv.append(model.getPos());
csv.append("\n");
model.updatePos();
view.repaint();
time += delta * 0.001;
if (counter>100) {
timer.stop();
PrintWriter pw;
try {
pw = new PrintWriter("data.csv");
pw.println(csv);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
}
Model
:
import java.util.ArrayList;
public class Model {
public int numberofparticles;
public ArrayList<Particle> particlelist;
public StringBuilder position = new StringBuilder();
Model() {
particlelist = new ArrayList<Particle>();
numberofparticles = 100;
for (int i = 0; i < numberofparticles; i++) {
particlelist.add(new Particle());
}
}
public void updatePos() {
for (int i = 0; i < numberofparticles; i++) {
particlelist.get(i).x += 2*Math.cos(Math.random()*2*Math.PI);
particlelist.get(i).y += 2*Math.sin(Math.random()*2*Math.PI);
}
}
public StringBuilder getPos() {
for (int i=0; i < numberofparticles; i++) {
//position.setLength(0);
position.append(particlelist.get(i).x);
position.append(",");
position.append(particlelist.get(i).y);
position.append(",");
}
return position;
}
public class Particle {
private double x;
private double y;
public Particle(double setX,double setY) {
x = setX;
y = setY;
}
Particle() {
this(500+250*2*Math.cos(Math.random()*2*Math.PI),
300+150*2*Math.sin(Math.random()*2*Math.PI));
}
public double getX() {
return x;
}
public double getY() {
return y;
}
}
}
View
:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.*;
public class View extends JPanel{
Model model;
View(Model m){
model = m;
this.setPreferredSize(new Dimension(1010,610));
}
public void paint(Graphics g) {
g.setColor(Color.DARK_GRAY);
for (int i=0; i < model.numberofparticles; i++) {
g.fillOval((int)(model.particlelist.get(i).getX()), (int) (model.particlelist.get(i).getY()), 3, 3);
}
}
}
MyFrame
:
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JFrame;
public class MyFrame extends JFrame{
Model model;
View view;
MyFrame() {
Model model = new Model();
View view = new View(model);
Controller control = new Controller(model, view);
this.setBackground(Color.ORANGE);
this.add(BorderLayout.NORTH, control);
this.add(view);
this.pack();
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main( String[] args ) {
new MyFrame();
}
}
Edit: The code above is now complete and can be copy pasted to recreate the error.
In Model
, I've commented out a line which would reset the StringBuilder
after every run, but if I use this line then the data output to the CSV just becomes nothing. I have no idea why.
Without testing I believe that the error is that StringBuilder position
is a field in the model. In your code each call to getPos()
adds more to the same string builder. Instead getPos()
should first create a new string builder and keep it locally while adding the coordinates to it.
Also %n
in StringBuilder.append()
will never give you a newline. Either '\n'
, "\r\n"
or System.getProperty("line.separator")
should work, the last being the most correct.
As an aside, should the fields of the model be public
? I think you can safely declare them private
for better encapsulation.