【问题标题】:Drawing a circle based from user input in Java根据 Java 中的用户输入绘制圆
【发布时间】:2014-11-15 09:03:46
【问题描述】:

我一遍又一遍地尝试找到解决此问题的方法,但我似乎无法理解如何解决它。

我正在尝试编写一个简单的程序来在程序中使用这些规范绘制一个圆圈:

  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 的回答进行更新

圈类

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

    }

}

【问题讨论】:

    标签: java swing paintcomponent joptionpane


    【解决方案1】:

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

    来自Ellipse2D.Double

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

    另一种设计可能性

    1. Circle 类中有一个setSphere 方法,可以设置椭圆和重绘

      public void setSphere(Ellepse2D.Double sphere) {
          this.sphere = sphere;
          repaint();
      }
      
    2. 在显示帧之后仍然执行所有JOptionPane。似乎是对的。然后,当您获取值时,您可以在 Circle 类上调用 setSphere,并使用新的 Ellipse2D.Double,它将显示在面板中。

    其他说明:

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

    • 请参阅初始线程。 Swing 应用程序应该在 Launched on the Event Dispatch Thread 上运行。

    • 另外,Circle 类中不需要多余的 x, y, etc 值。它们已经被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);
        }
    }
    

    更新

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

    您可以做的只是在每个方法中调用 JOPtionPane。假设您只想获取 x,然后调用 JOptionPane,并基于该值,使用旧值并仅使用新 x 从旧 Ellipse 创建一个新 Ellipse。然后拨打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 中调用它们?你可以查看上面的代码,看看我在说什么。
    • 你可以做的就是在每个方法中调用JOPtionPane。假设您只想获取 x,然后调用 JOptionPane,并基于该值,使用旧值并仅使用新 x 从旧 Ellipse 创建一个新 Ellipse。然后拨打setSphere。给我一分钟的例子
    • 我在上面的原始代码下面的代码中添加了一个新的更新。我在 Circle 类的 public void inputX() 和 public void inputRadius() 以及 CircleTester 类的 public static void main() 中留下了一些 cmets。你能检查一下我做得对吗?
    • inputRadius 你没有使用r 值。您基本上只是在创建相同的椭圆。半径是半个圆。所以你不应该将它乘以 2 并将其用于高度和宽度。由于高度和宽度应该相同?看看我在getCircle() 方法中是如何做到的
    • 哦。所以我添加了 int size = r * 2;,对吗?如何从 public static void main(String[] args) 调用它?我尝试了类似 Circle.inputX(); 之类的东西,它说 “无法从 Circle 类型对非静态方法 inputX() 进行静态引用”
    【解决方案2】:
    1. 从 Circle 类中获取所有 UI,这意味着删除所有那些 JOptionPane 调用。
    2. 所有用户交互都应该在您的 CircleTester 类中。
    3. Circle 类不应专注于用户 IO,而应仅专注于绘制由其属性定义的 Circle。
    4. 为您的 Circle 类提供一个接受有意义参数的构造函数。
    5. 在我看来,不需要 Ellipse2D,因为您可以通过调用 g.drawOval(....)` 使用 Graphics 对象简单地绘制圆,从而简化您的程序。
    6. 在 CircleTester 中获取输入参数后,创建 Circle 对象,传入从 CircleTest 获得的参数,并显示您的 Circle。
    7. 另外,不要忘记在您的 paintComponent 方法覆盖中调用 super.paintComponent(g) 方法。
    8. 轻微的挑剔,但我不会声明周长和面积变量,而是提供您的 Circle 类 getCircumference()getArea() 方法,以便在需要时在现场计算这些。否则,如果您给 Circle 一个 setRadius(...) 方法,您必须记住更改 setter 方法中的其他字段,如果您将 radius 或其他字段公开,那么一切都可以打破。安全起见,只为这两个属性而不是字段提供访问器方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多