Related
I want to create a shape Object(in my case the object is a rectangle). Each time I click a button. Currently, I'm able to make it appear just once. The idea would be that each time I click the button, a new rectangle Object is created, additional to the old one. Therefore, if I click the button 5 times, I should have 5 rectangles.
I tried to do it with an ArrayList, but still, there is just one rectangle appearing. Does someone know how to do it!
Thank you very much in advance!
This is the main class, FYI there is also a rectangle Class(not attached)
import controlP5.*;
ControlP5 cp5;
Rectangle rect; // rect begins as null
Button rc;
ArrayList<Rectangle> rectList;
void setup(){
size(1000, 1000);
rectList = new ArrayList<Rectangle>();
cp5 = new ControlP5(this);
rc = cp5.addButton("Rectangle").
setPosition(5, 4).
setColorBackground(color(52, 55, 76));
rc.onRelease(new CallbackListener() {
public void controlEvent(CallbackEvent theEvent) {
// only create the rectangle when the button is clicked
rect = new Rectangle(100, 100, 100, 100);
}
});
}
void draw(){
background(255);
// if the rect exists, draw it on the screen
if(rect != null) {
rect.displayRect();
showRect();
}
for(int i = 0; i < rectList.size(); i++){
//((Rectangle)rectList.get(i)).update();
((Rectangle)rectList.get(i)).displayRect();
}
}
public void showRect(){
for(Rectangle r: rectList){
r.displayRect();
rect(r.getXvalue(), r.getYvalue(), r.getWvalue(), r.getHvalue());
}
}
You have a list, but you never add anything to that list. The list remains empty.
Drop the member field rect, delete this line:
Rectangle rect; // rect begins as null
When you instantiate a new Rectangle, immediately add it to the list.
rc.onRelease( new CallbackListener() {
public void controlEvent(CallbackEvent theEvent) {
// When the button is clicked, instantiate a new rectangle and remember it by adding to our list of rectangles.
rectList.add(
new Rectangle( 100, 100, 100, 100 )
);
}
});
Some chiding: This was not a good Question for Stack Overflow. You could easily have found this bug by using a debugger to step through the code. You would have seen that the list remains empty. Before posting, do your own debugging exhaustively.
You should post your Rectangle class to make it easier for others to test and help out.
As Basil pointed out (+1) you're only rendering a new rectangle for one frame when there's a click event.
The idea would be that each time I click the button, a new rectangle Object is created, additional to the old one. Therefore, if I click the button 5 times, I should have 5 rectangles.
This statement is a bit ambiguous. I get you'd like to render a rectangle per click, however in the click handler the rect has the exact same dimensions and coordinates. Even if you would make minor fixes, rendering 5 identical rectangles on top of each other will likely appear as if it's a single rectangle.
Regarding the code you posted, this stands out to me:
Rectangle rect; // rect begins as null: what is the purpose of the rect if you have this underneath: ArrayList<Rectangle> rectList; ?
showRect(); is called in draw(): it loops over rectList and not only calls displayRect() which I'd assume would render the current rect, but also re-renders the same data on the following line (rect(r.getXvalue(), r.getYvalue(), r.getWvalue(), r.getHvalue());)
underneath, there's a for loop over the same list calling displayRect() yet again. My guess is 2 out 3 calls to render rectangles are redundant. (Also the array list is typed therefore, no need to cast like this: (Rectangle)rectList.get(i)), rectList.get(i) should suffice)
The only other minor caveat I have is around naming: ideally you would want to stick to Java naming conventions in Processing. (For example getXValue() instead of getXvalue(), etc.)
Regarding the ControlP5 button you could use controlEvent() which is a bit simpler than setting a callback. Even simpler is to use this automatic variable plugging functionality. In short, if a function has the same name as a button's name it will be called automatically:
Automatic controller-event detection
ControlP5 offers a range of controllers that allow you to easily change and adjust values while your sketch is running. Each controller is identified by a unique name assigned when creating a controller. ControlP5 locates variables and functions inside your sketch and will link controllers to matching variables or functions automatically
(from controlP5 reference)
Here's a basic example that prints a message to console each time the button is clicked:
import controlP5.*;
ControlP5 cp5;
void setup() {
size(1000, 1000);
cp5 = new ControlP5(this);
cp5.addButton("rectangle").
setPosition(5, 4).
setColorBackground(color(52, 55, 76));
}
void draw(){
background(255);
}
void rectangle(){
println("rectangle button clicked");
}
(I've kept the name rectangle instead of Rectangle to keep in line with Java naming conventions. The text label is displayed in uppercase anyway)
Back to your main question, if you want to add new rectangle per button press and render them the code be as simple as:
import controlP5.*;
ControlP5 cp5;
ArrayList<Rectangle> rectList = new ArrayList<Rectangle>();
int x = 100;
int y = 100;
void setup() {
size(1000, 1000);
rectList = new ArrayList<Rectangle>();
cp5 = new ControlP5(this);
cp5.addButton("rectangle").
setPosition(5, 4).
setColorBackground(color(52, 55, 76));
}
void draw() {
background(255);
for (int i = 0; i < rectList.size(); i++) {
rectList.get(i).display();
}
}
void rectangle(){
rectList.add(new Rectangle(x, y, 100, 100));
// increment x, y to avoid superimposed rectangles
x += 50;
y += 50;
}
class Rectangle{
private int x, y, w, h;
Rectangle(int x, int y, int w, int h){
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
void display(){
rect(x, y, w, h);
}
// currently not used
public int getX(){
return x;
}
public int getY(){
return x;
}
public int getWidth(){
return x;
}
public int getHeight(){
return x;
}
}
Rectangle rect; stands out. If this was an OOP homework assignment or exercise perhaps the intention was to have a basic drawing app functionality where the user could have a rectangle drawing tool ?
If that's the case rect could be selection rectangle which could cloned into rectList so it persists.
You could implement rectangle selection like so:
when the mouse is pressed remember the coordinates: these are the starting point of the selection
as the mouse is dragged the end point coordinates are the current mouse coordinates, hence the selection rectangle dimensions are the difference between the current mouse coordinates and the previously stored mouse coordinates
as the mouse is released, reset the selection rectangle (so it no longer displays)
Here's a basic example sketch:
Rectangle selection = new Rectangle(0, 0, 0, 0);
void setup(){
size(1000, 1000);
}
void draw(){
background(255);
selection.display();
}
void mousePressed(){
// store selection start
selection.x = mouseX;
selection.y = mouseY;
}
void mouseDragged(){
// update selection dimension as the difference between the current mouse coordinates and the previous ones (selection x, y)
selection.w = mouseX - selection.x;
selection.h = mouseY - selection.y;
}
void mouseReleased(){
selection.w = selection.h = selection.x = selection.y = 0;
}
class Rectangle{
private int x, y, w, h;
Rectangle(int x, int y, int w, int h){
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
void display(){
rect(x, y, w, h);
}
}
Resetting the Rectangle properties to 0 could be nicely encapsulated into a method:
void reset(){
x = y = w = h = 0;
}
The release handler would also be useful to add a new rectangle to rectList which has the same properties (x, y, w, h) as the selection, but before the selection is reset. something like:
void mouseReleased(){
// add a copy of the selection to rectList
rectList.add(new Rectangle(selection.x, selection.y, selection.w, selection.h));
// reset selection
selection.reset();
}
Again, the copy functionality is something that could be nicely encapsulated as a method as well:
Rectangle copy(){
return new Rectangle(x, y, w, h);
}
Putting it all together would look like this:
import controlP5.*;
ControlP5 cp5;
ArrayList<Rectangle> rectList = new ArrayList<Rectangle>();
Rectangle selection = new Rectangle(0, 0, 0, 0);
void setup() {
size(1000, 1000);
rectList = new ArrayList<Rectangle>();
cp5 = new ControlP5(this);
cp5.addButton("rectangle").
setPosition(5, 4).
setColorBackground(color(52, 55, 76));
}
void draw() {
background(255);
// draw previous rectangles (black)
stroke(0);
for (int i = 0; i < rectList.size(); i++) {
rectList.get(i).display();
}
// draw current selection (green)
stroke(0, 192, 0);
selection.display();
}
void rectangle(){
println("selected drawing tool is rectangle");
}
void mousePressed(){
// store selection start
selection.x = mouseX;
selection.y = mouseY;
}
void mouseDragged(){
// update selection dimension as the difference between the current mouse coordinates and the previous ones (selection x, y)
selection.w = mouseX - selection.x;
selection.h = mouseY - selection.y;
}
void mouseReleased(){
// add a new rectangle to the list: a copy of the selection
rectList.add(selection.copy());
// reset selection
selection.reset();
}
class Rectangle{
private int x, y, w, h;
Rectangle(int x, int y, int w, int h){
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
void display(){
rect(x, y, w, h);
}
Rectangle copy(){
return new Rectangle(x, y, w, h);
}
void reset(){
x = y = w = h = 0;
}
}
At this stage the button is a bit redundant, however it could useful in the future if other shapes are required (e.g. an Ellipse would be an obviously simple one to implement since ellipse() has the same parameters as rect(), just need to ensure ellipseMode(CORNER) is set to use the same selection x,y coordinates the rectangle does)
Hopefully this is useful. The initial code, as mentioned before looks a bit messy, as if it's put together in a haste before a deadline.
(I assume this because it reminds me of my code as a student :))
I'd recommend taking a short walk away from the computer, remembering what the task is and pen on paper breaking the task into small, clear, easy to implement subtasks. Once that is as clear as it can be, implement one subtask at a time in isolation. Initially the code may break or get messy, but eventually it will work (and it will be easier to write compared to the whole drawing program). Once that works, cleanup the code so that all unnecessary code is removed and it's easy to move the code to another sketch and run it without errors. Repeat the process for each subtask which should result in multiple minimal sketches solving one single problem. Once all parts are solved in isolation you can start putting the code together into one main sketch, however I recommend adding one subtask code as a time and testing first. When mixing code from multiple sketches conflicts/errors may arise and it will far easier to tackle merging two sketches a time than all of the subtask sketches in one go. Best of luck !
I have been unable to find an answer to this issue, so hopefully someone can help me out.
I am doing a class assignment where I have to make a scene using graphics. We've only had two lectures covering graphics so far, so I am hardly familiar. The issue is that she methods are not being painted in the preferred order. As you can see in the code to follow, I have two recursive methods making a sky and grass background/foreground. On top of those, I wish to have a cross (as well as many components thereafter granted I can get past this problem), but the cross does not appear as it should despite having that being the last method called within paint.
import java.awt.*;
import javax.swing.*;
public class DrawPicture extends JApplet
{
public final int SIZE = 800;
public final int DIST = 20;
public Color bg1 = new Color(0, 200, 255);
public Color bg2 = new Color(0, 175, 255);
public Color grass1 = new Color(0, 220, 60);
public Color grass2 = new Color(30, 255, 150);
public Color brown = new Color(110, 80, 20);
public void backgroundRec(int x, int y, int c, Graphics g)
{
if (c%2==0)
g.setColor(bg1);
else if (c%2==1)
g.setColor(bg2);
if (c < 40)
{
g.fillOval(x, y, SIZE, SIZE);
backgroundRec(x, y - DIST, c+1, g);
}
}
public void foregroundRec(int x, int y, int c, Graphics g)
{
if (c%2==0)
g.setColor(grass1);
else if (c%2==1)
g.setColor(grass2);
if (x < SIZE/2)
{
g.fillRect(x, y, SIZE, DIST);
foregroundRec(x, y + DIST, c+1, g);
}
}
public void cross(int x, int y, Graphics g)
{
g.setColor(brown);
g.fillRect(SIZE/2, SIZE/2, 45, 275);
g.fillRect(SIZE/2-50, SIZE/2+45, 150, 45);
}
public void paint(Graphics g)
{
//backgroundRec(0, 0, 0, g);
//foregroundRec(0, 400, 0, g);
cross(SIZE/2, SIZE/2, g);
}
}
One of the problems is, you have a StackOverflowException in foregroundRec, because nothing is seems to be stopping it from updating, probably because you're not changing the value of x.
I "think" foregroundRec(x, y + DIST, c + 1, g); should be foregroundRec(x + DIST, y + DIST, c + 1, g); or something :P - but based on your code, x has to change
You should also be calling super.paint before you do any of your own painting, this ensures that you don't end up with any weird paint artifacts
The other problem you're having is the fact that you're relying on the SIZE property, instead, you should be using getWidth or getHeight to determine what the actual size of the applet is
I'd also suggest having a look at:
Java Plugin support deprecated and Moving to a Plugin-Free Web
Painting in AWT and Swing
Performing Custom Painting
2D Graphics
Updated
Okay, after going through a few iterations, what I actually think you're trying to do is...
if (y < SIZE) {
g.fillRect(x, y, SIZE, DIST);
foregroundRec(x, y + DIST, c + 1, g);
}
Table t1= new Table(300, 300);
float power=0;
float dx=0;
float dy=0;
void setup()
{
size(1000, 600);
frameRate(10);
}
void draw()
{
strokeWeight(1);
stroke(0, 0, 0);
strokeWeight(10);
stroke(255, 0, 0);
fill(26, 218, 35);
rect(0, 0, 1000, 600);
noStroke();
fill(0);
ellipse(0, 0, 80, 80);
ellipse(1000, 0, 80, 80);
ellipse(0, 600, 80, 80);
ellipse(1000, 600, 80, 80);
strokeWeight(1);
stroke(0, 0, 0);
fill(255);
ellipse(t1.cue_ball.center.x, t1.cue_ball.center.y, 20, 20);
dx=friction(dx);
dy=friction(dy);
if (mousePressed)
{
power+=5;
}
if (t1.cue_ball.center.x+30>1000 || t1.cue_ball.center.x-30<0)
{
dx*=-1;
}
if (t1.cue_ball.center.y+30 >=600 || t1.cue_ball.center.y -30<=0)
{
dy*=-1;
}
t1.cue_ball.center.x +=dx;
t1.cue_ball.center.y +=dy;
}
void mouseReleased()
{
dx=power*2;
dy=power*2;
}
float friction (float c)
{
c*=0.9;
return c;
}
class Ball
{
float rad;
Point center;
Point contact_point;
color col;
Ball ( float a, float b)
{
center = new Point (a+=dx, b+=dy);
//contact_point= new Point(
}
}
class Table
{
Ball [] b_arr;
Stick st;
Ball cue_ball;
Table ( float a, float b )
{
cue_ball= new Ball( a, b);
}
}
class Point
{
float x;
float y;
Point(float a, float b)
{
x=a;
y=b;
}
}
class Stick
{
Point start_p;
Point end_p;
color col;
int length;
}
So we want to add something so that when the ball is clicked, it will move accordingly. For example, if it is clicked in the top left, it will move diagonally right down. If clicked bottom left, it will move diagonally right up. Also, is there a way to correspond this to the angle? So a larger angle between the click point and the center will make a steeper diagonal.
Added lines of code I'm not sure where needs to be added:
t1.cue_ball.center.x+=dx;
t1.cue_ball.center.y+=dy;
dx=t1.cue_ball.center.x-mouseX;
dy=t1.cue_ball.center.y-mouseY;
float n= sqrt(pow(dx,2)+pow(dy,2));
dx*=power/n;
dy*=power/n;
If you have or know how to compute the angle between the x-axis and the cue (I'm assuming this is billiards), then to make the ball go in that direction, if I understand your code correctly, you could just set the dx and dy of the ball that you strike according to
dx = power*cos(angle)
dy = power*sin(angle)
You might have to take the negative angle instead, depending on the coordinate system (if going up is positive or negative in the y-direction), and precisely what angle you compute. The easiest is probably to just plug it in and see what happens!
EDIT:
Not related to your question, but as a matter of style, it might be a good idea to move your logic for moving and drawing the ball to the Ball class. So that every tick, you draw the balls on the screen by calling an appropriate draw() method for each instance of the Ball class. Then it would be much easier to move several balls at once.
EDIT2:
I just realized you can actually solve the problem without trigonometry, if you know the point where you click. Let's say cx,cy is the point where you click, and x,y is the center of the ball, then your dx and dy for the ball can be computed as:
dx = x-cx
dy = y-cy
n = sqrt(dx^2 + dy^2)
dx *= power/n
dy *= power/n
Explanation:
The outgoing velocity for the ball should be in the same direction as the click relative to the ball. So we already have the relative lengths of dx and dy, and to get the right power we just need to normalize and multiply by the power.
I have a graphic which consists of a horizontal line of circles of different sizes at regular intervals. Here is the picture:
I am trying to recreate this graphic using recursion as opposed to the if statements used in my code but after trying, am unsure about how to do this. Would love some help, here is my code:
package weekFour;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.*;
#SuppressWarnings("serial")
public class Circle extends JPanel {
private int circX = 10;
private static int windowW = 1700;
private static int windowH = 1000;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); //smoothes out edges
Color c5 = new Color(50, 50, 50);
Color c4 = new Color(100, 100, 100);
Color c3 = new Color(150, 150, 150);
Color c2 = new Color(200, 200, 200);
Color c1= new Color(250, 250, 250);
for (int i = 0; i < 1; i++) {
g2.setColor(c1);
g2.fillOval(522 + 75*i, 138, 666, 666);
g2.setColor(c1);
g2.drawOval(522 + 75*i, 138, 666, 666);
}
for (int i = 0; i < 3; i++) {
g2.setColor(c2);
g2.fillOval(244 + 522*i, 365, 180, 180);
g2.setColor(c2);
g2.drawOval(244 + 522*i, 365, 180, 180);
}
for (int i = 0; i < 10; i++) {
g2.setColor(c3);
g2.fillOval(130 + 174*i, 428, 60, 60);
g2.setColor(c3);
g2.drawOval(130 + 174*i, 428, 60, 60);
}
for (int i = 0; i < 25; i++) {
g2.setColor(c4);
g2.fillOval(60 + 87*i, 444, 25, 25);
g2.setColor(c4);
g2.drawOval(60 + 87*i, 444, 25, 25);
}
for (int i = 0; i < 120; i++) {
g2.setColor(c5);
g2.fillOval(circX + 29*i, 450, 12, 12);
g2.setColor(c5);
g2.drawOval(circX + 29*i, 450, 12, 12);
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("MyTaskToo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new Circle());
frame.setSize(windowW, windowH);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Thanks for your time.
This is how I went about this problem, although we had to do it with green circles as opposed to grey circles but it's not that different.
N.B: Sorry for the appealing comments for sometimes trivial things but we get marks for commenting and it is better to be safe than sorry. Maybe they change you some insight into the thought process.
Here is the main method that starts the programme and sets out the window information.
public class Q2Main {
public static void main(String[] args) {
// here we are just setting out the window end putting the circles drawin in Q2Circles into this window.
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(1000, 500);
window.getContentPane().add(new Q2Circles(5));
window.setVisible(true);
}}
This is where the magic happens:
public class Q2Circles extends JPanel {
// this allows the user to specify how many loops of recursion they want the programme to complete before finishing
int recursionsToDo;
public Q2Circles(int recursionMax){
super();
recursionsToDo = recursionMax;
}
/*
this method is automatically called when we run the constructor as it inherits from the JFram superclass. here
we are setting out the size of the circle by getting the size of the window to make it proportional to the rest
of the screen and circles.
we then pass these values into the drawCircle method to draw the circle
*/
public void paintComponent(Graphics g){
Rectangle rectangle = this.getBounds();
int diameter = rectangle.width/3;
int centerPoint = rectangle.width/2;
drawCircle(g, 1, centerPoint, diameter);
}
/*
This method is where the magic of the programme really takes place. first of all we make sure we haven't completed
the necessary recursions. we the set the color by dividing it by the amount of times we have recursed, this will
have the affect of getting darker the more times the method recurses. we then sset the color. finaly we fill the
oval (draw the circle). because we want to move depending on the times it has recursed and size of the previous
we do it based on the size of the elements from the previous call to this method. Getting the right numbers
though was just alot of trial and error.
we then increment the recursion counter so that we know how many times we have recursed and that can then be
used at different points where needed. e.g for setting the color.
each recursive call used the dimension of the other recursive calls to make the whole picture. Although the
first recursive call creates the circles on the right of the screen. the second call draws the circle on the
left of the screen and the last one does the circles in the middle, they all use eachothers values to make it
complete. without one recursive step, more is missing than just what is created by that recursive call on its own.
in all honesty though, there is alot of duplication, like the large middlecircle.
*/
public void drawCircle(Graphics g, int amountOfRecursions, int center, int diameter){
if (amountOfRecursions <= recursionsToDo){
int recursionsCount = amountOfRecursions;
int greenColor = Math.round(225 / (amountOfRecursions));
g.setColor(new Color(0, greenColor, 0));
g.fillOval(center - (diameter/2), 200 - (diameter/2), diameter, diameter);
recursionsCount++;
drawCircle(g, recursionsCount, Math.round(center + diameter), diameter/3);
drawCircle(g, recursionsCount, Math.round(center - diameter), diameter/3);
drawCircle(g, recursionsCount, Math.round(center), diameter/3);
}
}}
I'm currently working on a program where certain numerical variables, which evolve over time, have their value displayed on each iteration. That works well enough, but now I want to plot a graph that shows their evolution over time.
So, I looked into an example of code for plotting graphs in Swing. My final code looks like this:
public class Populus3 extends JPanel
{
public static void main(String[] args) throws IOException {
final Populus3 pop = new Populus3();
JFrame f = new JFrame(); //where I want to plot the graph
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new GraphingData());
f.setSize(400,400);
f.setLocation(200,200);
f.setVisible(true);
frame = new JFrame("Animation Frame"); //where I'm running animation for another element of the program
frame.add(pop, BorderLayout.CENTER);
frame.setSize(graphSize, graphSize);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//insert all sort of things
}
public void paint(Graphics g)
{
super.paint(g);
paintCell(g, 1);
Toolkit.getDefaultToolkit().sync(); // necessary for linux users to draw and animate image correctly
g.dispose();
}
public void actionPerformed(ActionEvent e) {
repaint();
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
for(int i = 0; i < particleType.length; i++)
paintCell(g, i); //a method that draws a small circle for the animation panel
}
public static class GraphingData extends JPanel {
int[] data = {
21, 14, 18, 03, 86, 88, 74, 87, 54, 77,
61, 55, 48, 60, 49, 36, 38, 27, 20, 18
};
final int PAD = 20;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int w = getWidth();
int h = getHeight();
// Draw ordinate.
g2.draw(new Line2D.Double(PAD, PAD, PAD, h-PAD));
// Draw abcissa.
g2.draw(new Line2D.Double(PAD, h-PAD, w-PAD, h-PAD));
double xInc = (double)(w - 2*PAD)/(data.length-1);
double scale = (double)(h - 2*PAD)/getMax();
// Mark data points.
g2.setPaint(Color.red);
for(int i = 0; i < data.length; i++) {
double x = PAD + i*xInc;
double y = h - PAD - scale*data[i];
g2.fill(new Ellipse2D.Double(x-2, y-2, 4, 4));
}
}
private int getMax() {
int max = -Integer.MAX_VALUE;
for(int i = 0; i < data.length; i++) {
if(data[i] > max)
max = data[i];
}
return max;
}
}
}
Now, the animation panel works just fine. The graph panel, on the other hand...when I run the program, it displays a bunch of red dots, without lines to connect them. What am I doing wrong?
In addition to #Hovercraft's helpful suggestions, also consider these other approaches:
Accumulate the points in a GeneralPath that may be rendered as required, for example.
Connect the points using repeated calls to drawLine() using a suitable coordinate system, outlined here.
Look at JFreeChart.
Your code confuses me:
You override both paint and paintComponent for your Populus3 JPanel -- why? You should only override paintComponent unless you absolutely have to have your drawing affect a component's children and borders.
You dispose of the Graphics object passed into paint -- a very dangerous thing to do. You should never dispose of a Graphics object given to you by the JVM, only Graphics objects that you yourself create.
You repeatedly call a method not defined here for us, paintCell(...).
I've never heard of the need for Toolkit.getDefaultToolkit().sync(); for Swing applications. Do you have a reference for this need?
You mention "animation" but I see no animation code.
In your GraphingData class's paintComponent method you fill ellipses in your for loop, but you don't connect them with lines ever, so it shouldn't be surprising that you're only seeing dots in your graph and no lines.
Consider isolating your problem more and posting an sscce, a minimal test program that we can compile, run, modify and correct and that shows us your problem, but has no extra code not related to the problem or required for demonstration.
The following code demonstrates a real-time Java chart using XChart where the line is updated as the data evolves over time. Creating real-time charts is as simple as calling updateXYSeries for one or more series objects through the XYChart instance and triggering a redraw of the JPanel containing the chart. This works for all chart types including XYChart, CategoryChart, BubbleChart and PieChart, for which example source code can be found here: https://github.com/timmolter/XChart/tree/develop/xchart-demo/src/main/java/org/knowm/xchart/demo/charts/realtime. Examples demonstrate using the SwingWrapper with repaintChart() method as well as XChartPanel with revalidate() and repaint(). Disclaimer, I'm the main developer of the XChart library.
public class SimpleRealTime {
public static void main(String[] args) throws Exception {
double phase = 0;
double[][] initdata = getSineData(phase);
// Create Chart
final XYChart chart = QuickChart.getChart("Simple XChart Real-time Demo", "Radians", "Sine", "sine", initdata[0], initdata[1]);
// Show it
final SwingWrapper<XYChart> sw = new SwingWrapper<XYChart>(chart);
sw.displayChart();
while (true) {
phase += 2 * Math.PI * 2 / 20.0;
Thread.sleep(100);
final double[][] data = getSineData(phase);
chart.updateXYSeries("sine", data[0], data[1], null);
sw.repaintChart();
}
}
private static double[][] getSineData(double phase) {
double[] xData = new double[100];
double[] yData = new double[100];
for (int i = 0; i < xData.length; i++) {
double radians = phase + (2 * Math.PI / xData.length * i);
xData[i] = radians;
yData[i] = Math.sin(radians);
}
return new double[][] { xData, yData };
}
}
This results in the following Java Swing real-time chart app: