1

For the purposes of my project, I'm trying to simulate a phyllotaxis pattern by creating multiple circles in real time using the formulas given.

So recently, I've decided to try out GUI programming in Java using JFrame and swing, and I've hit a wall trying to figure out how to get everything running properly. My idea was to slowly print out circle after circle with their x and y coordinates being calculated from the "r = cos/sin(theta)" formulas documented in the phyllotaxis instructions. Unfortunately, while the x and y values are constantly changing, only one circle is printed. Is there something I am missing?

package gExample;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.Timer;


public class GraphicsExample extends Canvas implements ActionListener {

private final static int HEIGHT = 600; 
private final static int WIDTH = 600; 
private int n = 0;
private int x, y;
Timer t = new Timer(20, this);

public static void main(String args[]) {
    JFrame frame = new JFrame();
    GraphicsExample canvas = new GraphicsExample();

    canvas.setSize(WIDTH, HEIGHT);
    frame.add(canvas);
    frame.pack();
    frame.setVisible(true);
    frame.setResizable(false);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    canvas.setBackground(Color.black);
}

public void paint(Graphics g){ 
    Random rand = new Random();

    Color col = new Color(rand.nextInt(256), rand.nextInt(256), rand.nextInt(256));
    g.setColor(col);

       /*each time paint() is called, I expect a new circle to be printed in the
        x and y position that was updated by actionPerformed(), but only one inital circle is created. */
    g.fillOval(x, y, 8, 8);

    t.start();

}


@Override
public void actionPerformed(ActionEvent e) {
    // TODO Auto-generated method stub

    int c = 9;
    double r = c * Math.sqrt(n);
    double angle = n * 137.5;

    //here, every time the method is called, the x and y values are updated, 
   //which will be used to fill in a new circle
    int x = (int) (r * Math.cos(angle * (Math.PI / 180) )) + (WIDTH / 2);
    int y = (int) (r * Math.sin(angle * (Math.PI / 180) )) + (HEIGHT / 2);

    //when the program is running, this line of code is executed multiple times.
    System.out.println("x: " + x + " y: " + y);

    n++;

}




}
Darien Miller
  • 651
  • 2
  • 7
  • 16
  • 1
    The custom painting in a Swing or AWT component is not 'persistent'. To get the effect you want, either a) retain a list of the earlier co-ords (etc.) then iterate the entire list and paint each, for every time the display must update, or.. b) write the changes to a buffered image displayed in a label, then repaint the label when the image changes. – Andrew Thompson Jan 02 '19 at 02:52
  • 1
    BTW - 1) `t.start();` That is not something that should appear in a `paint(Graphics)` method. 2) Using AWT components for custom painting is mostly unnecessary. I'd use a `JPanel` instead. 3) Whether using Swing (`paintComponent(Graphics)`) or AWT (`paint(Graphics)`), always call the `super` method. Doing so ***guarantees*** that previous drawings are erased. It often occurs anyway, as you've observed, but best not leave it to chance. – Andrew Thompson Jan 02 '19 at 02:56
  • Option A makes complete sense, but option B is a little bit vague. Can you elaborate a bit more what a label and buffered image is? Also where should t.start() go? – Darien Miller Jan 02 '19 at 04:19
  • A [`JLabel`](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/swing/JLabel.html) can display an `ImageIcon` which contains a [`BufferedImage`](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/image/BufferedImage.html). Here is [an example](https://stackoverflow.com/a/14575043/418556)? *"Also where should t.start() go?"* The paint method is called whenever the JRE determines it's needed, and may be called many times. The constructor in guaranteed to be called exactly once, so that's where I'd put it. But better to use a Swing `Timer` (see earlier eg) – Andrew Thompson Jan 02 '19 at 05:29

0 Answers0