I have tried over and over to find a solution to this problem, but I seem to can't understand how to solve it.
I'm trying to write a simple program to draw a circle with these specifications in the program:
Somehow, it won't draw the circle, and calculate the circumference and area. Can you please help me find a solution to this problem?
Here are my codes:
------- main -------
package circleSquarePackage;
import circleSquarePackage.Circle;
import javax.swing.JOptionPane;
import javax.swing.JFrame;
public class CircleTester {
public static void main(String[] args)
{
JFrame frame = new JFrame();
// Display Circle in the frame
frame.setSize(600, 500);
frame.setTitle("CircleSquare");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Create Circle Components
Circle round = new Circle();
frame.add(round);
frame.setVisible(true);
}
}
-------- other class ---------
package circleSquarePackage;
import javax.swing.JComponent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Ellipse2D.Double;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Color;
import javax.swing.JOptionPane;
public class Circle extends JComponent {
// Member instance field
private Ellipse2D.Double sphere;
private int radius;
double circumference, area;
String x1; // starting x co-ordinate
String y1; // starting y co-ordinate
String r1; // radius for circle
String draw;
int x = 0;
int y = 0;
int r = 0;
// Default constructor
public Circle()
{
sphere = new Ellipse2D.Double();
}
// User defined constructor
public Circle(int xAxis, int yAxis, int rad)
{
rad = r;
xAxis = x;
yAxis = y;
sphere = new Ellipse2D.Double(xAxis, yAxis, rad, rad);
}
// Accessor methods
public double calcCircumference()
{
return circumference = 2 * Math.PI * radius;
}
public double calcArea()
{
return area = Math.PI * radius * radius;
}
// Methods
public void inputX()
{
x1 = JOptionPane.showInputDialog(null, "Input center (x value): ");
x = Integer.parseInt(x1);
}
public void inputY()
{
y1 = JOptionPane.showInputDialog(null, "Input center (y value): ");
y = Integer.parseInt(y1);
}
public void inputRadius()
{
r1 = JOptionPane.showInputDialog(null, "Input radius: ");
r = Integer.parseInt(r1);
}
public void paintComponent(Graphics g)
{
// Cast 1D to 2D graphics
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.BLUE); // set circle color to blue
g2.fill(sphere);
g2.draw(sphere);
g2.setColor(Color.BLUE);
g2.drawString("Circumference = " + calcCircumference(), 5, 450);
g2.drawString("Area = " + calcCircumference(), 200, 450);
}
}
UPDATE BASED ON PEESKILLET'S ANSWER
Circle class
package circleSquarePackage;
import javax.swing.JComponent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Ellipse2D.Double;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JOptionPane;
public class Circle extends JComponent {
// Member instance field
private Ellipse2D.Double sphere;
private int radius;
double circumference, area;
// Default constructor
public Circle()
{
sphere = new Ellipse2D.Double();
}
public void setSphere(Ellipse2D.Double sphere) {
this.sphere = sphere;
repaint();
}
// User defined constructor
public Circle(int xAxis, int yAxis, int rad)
{
sphere = new Ellipse2D.Double(xAxis, yAxis, rad, rad);
}
// Accessor methods
public double calcCircumference()
{
return circumference = 2 * Math.PI * radius;
}
public double calcArea()
{
return area = Math.PI * radius * radius;
}
// Methods
public void inputX()
{
int x = Integer.parseInt(JOptionPane.showInputDialog(null, "Enter x"));
double y = sphere.y; // why is there a double y here when it asks for x?
Ellipse2D.Double newSphere = new Ellipse2D.Double(x, y, size, size);
setSphere(newSphere);
}
public void inputY()
{
int y = Integer.parseInt(JOptionPane.showInputDialog(null, "Enter y"));
double x = sphere.x;
Ellipse2D.Double newSphere = new Ellipse2D.Double(x, y, size, size);
setSphere(newSphere);
}
public void inputRadius()
{
// is this how I do for radius?
int r = Integer.parseInt(JOptionPane.showInputDialog(null, "Enter radius"));
int size = r * 2;
Ellipse2D.Double newSphere = new Ellipse2D.Double(x, y, size, size);
setSphere(newSphere);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.BLUE); // set circle color to blue
g2.fill(sphere);
g2.draw(sphere);
g2.drawString("Circumference: " + calcCircumference(), 5, 490);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(600, 500);
}
}
-------- CircleTester class --------
package circleSquarePackage;
import circleSquarePackage.Circle;
import javax.swing.JOptionPane;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Ellipse2D.Double;
public class CircleTester {
/*
private static Ellipse2D.Double getCircle() {
int x = Integer.parseInt(JOptionPane.showInputDialog(null, "Enter integer for x-coordinates:"));
int y = Integer.parseInt(JOptionPane.showInputDialog(null, "Enter integer for y-coordinates:"));
int radius = Integer.parseInt(JOptionPane.showInputDialog(null, "Enter radius of circle:"));
int size = radius * 2;
return new Ellipse2D.Double(x, y, size, size);
}*/
public static void main(String[] args)
{
// Is there a way to call the inputX(), inputY(), and inputRadius() here?
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.setTitle("CircleSquare");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Circle round = new Circle();
frame.add(round);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
/*
Ellipse2D.Double newCircle = getCircle();
round.setSphere(newCircle);
*/
}
});
}
}
In your no-arg Circle
constructor, you're creating a sphere
(default Ellipse2D.Double
) before you get the values. You should create the sphere
based on the those values, like you are in the three-arg constructor
From Ellipse2D.Double
Ellipse2D.Double()
Constructs a new Ellipse2D, initialized to location (0, 0) and size (0, 0).
Another Design Possibility
Have a setSphere
method in the Circle
class, that you can set the ellipse and repaint
public void setSphere(Ellepse2D.Double sphere) {
this.sphere = sphere;
repaint();
}
Do all your JOptionPane
still after the frame is shown. Just seems right. Then when you get the values, you can call setSphere
on the Circle
class, with a new Ellipse2D.Double
and it will show in the panel.
Other Notes:
When doing custom painting, better to override getPreferredSize()
on the painted component, and just call pack()
on the frame, instead of setSize()
See Initial Threads. Swing apps should be run on the Launched on the Event Dispatch Thread.
Also you don't need redundant x, y, etc
values in the Circle
class. They are already being held by the Ellipse
object. If you need to get some values, just get it from that, i.e. sphere.x
, sphere.y.
, etc
Here's a refactor of the suggestions I mentioned above. (You will also want to do some checks to make sure an number is actually type. I was being lazy)
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
public class CircleTester {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.setTitle("CircleSquare");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Circle round = new Circle();
frame.add(round);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Ellipse2D.Double newCircle = getCircle();
round.setSphere(newCircle);
}
});
}
private static Ellipse2D.Double getCircle() {
int x = Integer.parseInt(JOptionPane.showInputDialog(null, "Enter x"));
int y = Integer.parseInt(JOptionPane.showInputDialog(null, "Enter x"));
int radius = Integer.parseInt(JOptionPane.showInputDialog(null, "Enter x"));
int size = radius * 2;
return new Ellipse2D.Double(x, y, size, size);
}
}
class Circle extends JComponent {
private Ellipse2D.Double sphere;
public Circle() {
sphere = new Ellipse2D.Double();
}
public void setSphere(Ellipse2D.Double sphere) {
this.sphere = sphere;
repaint();
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.BLUE); // set circle color to blue
g2.fill(sphere);
g2.draw(sphere);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
}
UPDATE
I was wondering how can I put the JOptionPane asking for user input in the Circle class under public void inputX(), public void inputY(), and public void inputRadius(), and then call those in the main in the CircleTester class?
What you can do is just call the JOPtionPane in each method. Say you want to just get x, then call the JOptionPane, and based on that value, create a new Ellipse from the old Ellipse using the old values and just using the new x. Then call setSphere
. Something like
public void inputX() {
int x = Integer.parseInt(JOptionPane.showInputDialog(null, "Enter x"));
double y = sphere.y;
double height = sphere.height;
double width = sphere.width;
Ellips2D.Double newSpehere = new Ellipse2D.Double(x, y, width, height);
setSphere(newSphere);
}
You can do this will the others as well. This way, when you call the method, once you input, it will only change the one variable.
You can also have one method to get all the variable, kind of like I did in my example.