Java中根据用户输入绘制一个圆形

4
我已经尝试了很多次来解决这个问题,但是似乎无法理解如何解决它。
我正在尝试编写一个简单的程序来绘制符合以下规格的圆形:
1.使用输入框(JOptionPane)询问用户圆的半径。 2.使用输入框(JOptionPane)询问用户圆的x和y坐标。 3.计算圆的周长。 4.计算圆的面积。 5.在圆形图下方显示面积和周长。
然而,它无法绘制圆形,也无法计算周长和面积。您能否帮助我找到解决此问题的方法吗?
以下是我的代码:
------- 主函数 -------
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);

    }

}

-------- 其他类 ---------

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);
    }
}

根据Peeskillet的回答更新

Circle类

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类 --------

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);
                */
            }
        });

    }

}
2个回答

5
在您的无参Circle构造函数中,在获取值之前,您正在创建一个sphere(默认为Ellipse2D.Double)。您应该基于这些值创建sphere,就像在三个参数的构造函数中一样。
来自Ellipse2D.Double

Ellipse2D.Double()
构造一个新的Ellipse2D,初始化位置为(0, 0)和大小为(0, 0)。

另一种设计可能性
  1. 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();
    }
    
  2. 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.

其他注意事项:

  • 在进行自定义绘制时,最好覆盖绘制组件的 getPreferredSize() 方法,然后只需在框架上调用 pack(),而不是 setSize()

  • 请查看“初始线程”。Swing 应用程序应在事件分派线程上运行。

  • 此外,在 Circle 类中不需要冗余的 x、y 等 值。它们已经由 Ellipse 对象保存。如果需要获取某些值,请从中获取,例如:sphere.xsphere.y 等。

这里是我上面提到的建议的重构。(您还需要进行一些检查,以确保数字实际上是类型。我有点懒)

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);
    }
}

更新

我想知道如何在Circle类的public void inputX(),public void inputY()和public void inputRadius()下放置JOptionPane来要求用户输入,然后在CircleTester类中调用它们?

您可以在每个方法中调用JOptionPane。例如您只想获取x,则调用JOptionPane,并根据该值,使用旧值创建一个新的Ellipse并仅使用新的x。然后调用 setSphere。类似这样:

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);
}

你也可以对其他变量执行相同的操作。这样,当你调用该方法时,一旦输入,它只会更改一个变量。

你还可以像我在例子中所做的那样,编写一个方法来获取所有变量。


谢谢你的帮助!这个可行!我在想如何将JOptionPane询问用户输入放在Circle类的public void inputX()、public void inputY()和public void inputRadius()下,然后在CircleTester类的main中调用它们?你可以查看上面的代码来了解我在说什么。 - user3768057
你可以在每个方法中调用 JOptionPane。比如说,如果你只想获取 x 的值,那么就调用 JOptionPane,并根据该值使用旧的值创建一个新的 Ellipse,然后调用 setSphere。稍等一下,我来给你举个例子。 - Paul Samsotha
我在原始代码下面添加了一个新的更新。我在Circle类中的public void inputX()和public void inputRadius(),以及CircleTester类中的public static void main()中留下了一些注释。你能否请检查一下我是否做得正确? - user3768057
inputRadius 你没有使用 r 值。你基本上只是创建了相同的椭圆。半径是一个圆的一半。所以你不应该将其乘以2并将其用于高度和宽度吗?因为高度和宽度应该相同。看看我在 getCircle() 方法中是如何做的。 - Paul Samsotha
哦,所以我要添加 **int size = r * 2;**,对吗?我怎么从 public static void main(String[] args) 调用它呢?我尝试了类似于 Circle.inputX(); 的东西,但它显示 **"Cannot make a static reference to the non-static method inputX() from the type Circle"**。 - user3768057
round.inputX()roundCircle 的实例。inputX() 是一个实例方法,不是静态方法。当你使用 Circle.inputX() 时,这是一个静态调用。你需要在 Circle 的实例上调用它。你应该对两者之间的区别进行一些研究。 - Paul Samsotha

3
  1. 将Circle类中所有UI移除,即删除所有JOptionPane调用。
  2. 所有用户交互都应该在CircleTester类中进行。
  3. Circle类应该专注于绘制由其属性定义的圆形,而不是用户IO。
  4. 为Circle类添加一个接受有意义的参数的构造函数。
  5. 我认为Ellipse2D并不需要,因为您可以通过调用g.drawOval(....)使用Graphics对象绘制圆形,从而简化程序。
  6. 在CircleTester中获取输入参数后,创建传递从CircleTest获得的参数的Circle对象,并显示您的Circle。
  7. 还要记得在paintComponent方法覆盖内调用super.paintComponent(g)方法。
  8. 小问题,但我不会声明circumference和area变量,而是为您的Circle类提供getCircumference()getArea()方法,在需要时直接计算这两个属性。否则,如果您为Circle类提供了setRadius(...)方法,则必须记住在setter方法中更改其他字段,如果使半径或其他字段公共,则可能会出现问题。安全起见,只需为这两个属性提供访问器方法,而不是字段。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接