为什么 JFrame Paint() 多次绘制同一点(或根本不绘制)?

问题描述 投票:0回答:1

上下文

我正在编写一个程序,使用蒙特卡洛方法近似 π 的值。
我的计划是让它直观地绘制 X 个点,并根据该图计算结果。

到目前为止的设计是这样的:

  1. 询问用户他们想要在近似值中使用多少个点。
  2. 询问用户他们希望模拟运行多快。
  3. 根据这些输入进行模拟。

快速警告:我是 Java 的新手 - 请原谅任何可怕的代码设置或愚蠢的问题。

问题

运行程序时,根据输入速度会发生以下两种情况之一:

a.) 对于慢速或中速,在计时器启动之前绘制两个点,并绘制第一个“真实”点。



b.) 对于快速或非常快的速度,第一个点会绘制两次。



由于某种原因,这也可能发生在第二点而不是第一点。



我不知道为什么会发生这种情况。以下是我尝试过的一些事情:

  • 调整输入点数
  • 调整绘制点的布尔条件
  • 使 JFrame 使用“虚拟”点作为第一个点,然后使用常规点
  • 调整重绘的布尔条件

我的课程

Main.java

public class Main {

    public static void main(String[] args) {
        SimSetup simSetup = new SimSetup();
        simSetup.simSetup();
        SimFrame frame = new SimFrame();
        SimDrawing d = new SimDrawing();
        frame.add(d);
        frame.setVisible(true);
    }
}

SimSetup.java

public class SimSetup {

    private final UserInput userInput = new UserInput();


    public void simSetup() {
        title.displayTitle();
        boolean startupSuccess = false;
        while (!startupSuccess) {
            userInput.setPoints();
            userInput.setPlotSpeed();
            if ((userInput.setVerification(userInput.getPoints(), 
                    userInput.getPlotSpeed()))) {
                break;
            }
        }
        SimDrawing.setPoints(userInput.getPoints());
        SimDrawing.setSpeed(userInput.getPlotSpeed());
    }
}  

用户输入.java

import java.util.InputMismatchException;
import java.util.Objects;
import java.util.Scanner;

public class UserInput {

    private int numPoints;
    private short plotSpeed;
    private String verification;


    public int getPoints() {
        return numPoints;
    }

    public short getPlotSpeed() {
        return plotSpeed;
    }

    public String getVerification() {
        return verification;
    }


    public int setPoints() {
        System.out.print("Enter the number of points to be plotted using a positive integer between 1 and 100,000: ");


        try {
            Scanner scanner = new Scanner(System.in);
            numPoints = scanner.nextInt();

            if (numPoints < 0) {
                System.out.println("\nNumber of points must be a positive integer. Please try again.\n");
                setPoints();
            } else if (numPoints == 0) {
                System.out.println("\nCan't generate a plot using zero points! Please try again.\n");
                setPoints();
            } else if (numPoints > 100000) {
                System.out.println("\nNumber of points is too large. Please try again.\n");
                setPoints();
            }

        } catch (InputMismatchException e) {
            System.out.println("\nThe number of points must be an integer between 1 and 100,000. Please try again.\n");
            setPoints();
        }
        return numPoints;
    }

    public short setPlotSpeed() {
        System.out.print("\nSelect a plotting animation speed from the choices below:");
        System.out.println("\n0 -- Slow\n1 -- Medium\n2 -- Fast\n3 -- Very Fast\n");

        try {
            Scanner scanner = new Scanner(System.in);
            short speedChoice = scanner.nextShort();

            if (speedChoice == 0) {
                plotSpeed = 100;
            } else if (speedChoice == 1) {
                plotSpeed = 50;
            } else if (speedChoice == 2) {
                plotSpeed = 10;
            } else if (speedChoice == 3) {
                plotSpeed = 1;
            }

        } catch (InputMismatchException e) {
            System.out.println("Speed must be an integer between 0 to 3. Please try again.");
        }
        return plotSpeed;
    }

    public boolean setVerification(long numPoints, short plotSpeed) {

        if (numPoints > 50000 && (plotSpeed == 100 || plotSpeed == 50)) {
            System.out.println("This combination of points and animation speed will result in long completion time.");
            System.out.println("Are you sure? (Y to continue, N to re-enter choices.)");

            try {
                Scanner scanner = new Scanner(System.in);
                verification = scanner.nextLine();
                verification = verification.toLowerCase();

                if (Objects.equals(verification, "n")) {
                    System.out.println("\nProcess aborted.\n");
                    return false;
                } else if (!Objects.equals(verification, "n") && !Objects.equals(verification, "y")) {
                    System.out.println("\nVerification input not recognized. Please try again.");
                    setVerification(numPoints, plotSpeed);
                    return false;
                }

            } catch (Exception e) {
                System.out.println("Exception: " + e);
            }
        }
        return true;
    }
}  

SimDrawing.java

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class SimDrawing extends JPanel implements ActionListener {


    int count = 0;
    int max = 525;
    int min = 75;
    int circleRadius = 450;
    int x = min + (int) (Math.random() * (max - min + 1));
    int y = min + (int) (Math.random() * (max - min + 1));
    private static int points;
    private static short speed;
    private int circlePoints;
    private int outsidePoints;
    Timer t = new Timer(speed, this);


    public static void setPoints(int numPoints) {
        points = numPoints;
    }

    public static void setSpeed(short plotSpeed) {
        speed = plotSpeed;
    }

    public SimDrawing() {
        t.start();
    }

    @Override
    public void actionPerformed(ActionEvent e) {

        System.out.println("\nCount: " + count);

        x = min + (int) (Math.random() * (max - min + 1));
        y = min + (int) (Math.random() * (max - min + 1));

        System.out.println("\nPoint generated: " + "(" + x + "," + y + ")");
        repaint();

        if (count == points) {
            t.stop();
            pointCheck();
        }
        count++;
    }

    public void paint(Graphics g) {

        Graphics2D g2d = (Graphics2D) g;
        double distanceFromCenter = (Math.sqrt(Math.pow((x - 75), 2) + Math.pow((y - 525), 2)));

        g2d.setColor(Color.BLACK);
        g2d.setStroke(new BasicStroke(2));
        g2d.drawLine(74, 74, 526, 74);
        g2d.drawLine(74, 74, 74, 526);
        g2d.drawLine(74, 526, 526, 526);
        g2d.drawLine(526, 74, 526, 526);


        g2d.setStroke(new BasicStroke(3));
        if (distanceFromCenter <= circleRadius) {
            g2d.setColor(Color.BLACK);
            g2d.drawLine(x, y, x, y);
            System.out.println("Plotting inside point: " + "(" + x + "," + y + ")");
            circlePoints++;
        }
        if (distanceFromCenter > circleRadius) {
            g2d.setColor(Color.RED);
            g2d.drawLine(x, y, x, y);
            System.out.println("Plotting outside point: " + "(" + x + "," + y + ")");
            outsidePoints++;
        }
    }

    public void pointCheck() {
        System.out.println("\nThe number of points inside the circle is: " + circlePoints);
        System.out.println("The number of points outside the circle is: " + outsidePoints);

        int totalMappedPoints = circlePoints + outsidePoints;

        System.out.println("The total number of points is: " + totalMappedPoints);
    }
}  

SimFrame.java

import javax.swing.*;
import java.awt.*;

public class SimFrame extends JFrame {
    public SimFrame() {

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setAlwaysOnTop(true);
        setTitle("Monte Carlo Method of Approximating π");
        setSize(616, 639);
        setResizable(false);
        setLayout(new GridLayout());
        setLocationRelativeTo(null);
    }
}
java plot jframe paint repaint
1个回答
0
投票

我想你可能错过了

Component#paint()
的作用,
当 JFrame 更新屏幕时,它会清除整个屏幕,然后所有内容都会被绘制。
这意味着您的所有内容都必须立即添加
Hopefully this explains what i mean

这意味着在代码中,您将需要 SimDrawing 中的一个变量,称为

/**Vector2 is a base java class, i think, if not find one online*/
List<Vector2> plottedPoints = new ArrayList<>();

然后,在paint函数中绘制这些点

for (Vector2 point : plottedPoints) {
   g2d.setColor(getColorOfPoint(point));
   g2d.drawOval(point.x-5, point.y-5, 10, 10);
}

课堂上的其他地方:

public static Color getColorOfPoint(Vector2 point) {
   return SimDrawing.isInsideCircle(point) ? Color.Red : Color.Blue;
}

另外还有

SimDrawing#actionPerformed(ActionEvent)
方法

points.add(new Vector2(x, y));
//Also add to the points in or outside
if (isInsideCircle(point))
   pointsInside++;
else
   pointsOutside++;

同班的其他地方:

public static Color isInsideCircle(Vector2 point) {
   ..The code you used earlier
}
© www.soinside.com 2019 - 2024. All rights reserved.