java - Java Swing 中的 Sierpinski Gasket 实现仅有时出现

标签 java swing

所以我必须使用 Swing 创建 Sierpinski 垫片的实现。 我不能使用递归或三角形。我必须使用以下内容 算法:

Pick 3 points to define a triangle.

Select one of the vertices as current Loop 50,000 times: Randomly choose a vertex as the target. Draw a pixel at the mid-point between the target and current. Make current the mid-point.

下图中是我有时在编译时得到的结果,但有时它会弹出然后消失,或者根本不显示。如果它确实出现,然后我调整窗口大小,它就会消失(我不关心这个,但如果它有帮助的话。)我有时只能在编译时生成下面的图像(大约 1/3 的时间。)下图是我的代码,分为两类。

Image of when it works

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


public class SierpinskiGasket {

    public static void main(String[] args) { 
        JFrame frame = new JFrame();
        frame.setTitle("SierpinskiGasket");
        frame.setSize(630,580);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


        drawSierpinski Sierpinski = new drawSierpinski();

        frame.add(Sierpinski);

        frame.setVisible(true);

        }
    }




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


public class drawSierpinski extends JPanel{

    Point point1 = new Point(10,550),
          point2 = new Point(300,30),
          point3 = new Point(600,555),
          current = point1, target;
    private int count = 0; 


    public void paintComponent(Graphics g){
        super.paintComponent(g);

            while(count<= 50000){
                int choice = (int)(Math.random()*3);
                switch(choice){
                    case 0: target = point1; break;
                    case 1: target = point2; break;
                    case 2: target = point3; break;
                    default: System.exit(0);

                }
                current = midpoint(current,target);
                g.drawLine(current.x,current.y,current.x,current.y);

                count++;
            }   
    }

    public Point midpoint(Point a, Point b){
        return new Point((Math.round(a.x+b.x)/2),
                         (Math.round(a.y+b.y)/2));
    }


}

我假设它与 Swing 的多线程处理方式有关,但不幸的是我对如何修复它没有太多了解。非常感谢您的帮助!

最佳答案

这个循环:

while(count<= 50000) { 

   // ....

}

可能需要一段时间才能完成,同时它将在最关键的时刻(绘图时)完全阻塞 Swing 事件线程。更重要的是,任何微不足道的重新绘制都会触发循环重新运行,再次完全卡住您的 GUI。

解决方案:在paintComponent 之外进行绘图。相反,创建一个 JPanel 大小的 BufferedImage,获取图像的 Graphics 对象,在 BufferedImage 中为三角形绘制随机点,然后在 JPanel 的 PaintComponent 方法中显示该图像。您可以在程序启动时绘制图像,然后在完成后启动 GUI,或者您可以启动 GUI 并在后台线程中绘制到 BufferedImage,并在完成后显示它,两者都可以(如果这是你的 GUI 唯一应该做的事情)。

例如:

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;

import javax.swing.*;

public class SierpTest {
    public static final int BI_WIDTH = 630;
    public static final int BI_HEIGHT = 580;

    public static void main(String[] args) {

        // do this stuff off the swing event thread
        final BufferedImage sierpImg = new BufferedImage(BI_WIDTH, BI_HEIGHT, BufferedImage.TYPE_INT_ARGB);
        Graphics g = sierpImg.getGraphics();

        // draw triangle with g here

        g.dispose(); // always dispose of any Graphics you create yourself

        // do this on the Swing event thread
        SwingUtilities.invokeLater(() -> {
            SierpPanel sierpPanel = new SierpPanel(sierpImg); // pass in image
            JFrame frame = new JFrame("Siep Frame");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(sierpPanel);
            frame.pack(); // size it to the size of the JPanel
            frame.setLocationRelativeTo(null); // center it
            frame.setVisible(true);
        });
    }
}

class SierpPanel extends JPanel {
    private BufferedImage img = null;

    public SierpPanel(BufferedImage img) {
        this.img = img;
    }

    // so that JPanel sizes itself with the image
    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet() || img == null) {
            return super.getPreferredSize();
        }
        return new Dimension(img.getWidth(), img.getHeight());
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (img != null) {
            g.drawImage(img, 0, 0, this);
        }
    }
}

例如:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.image.BufferedImage;

import javax.swing.*;

public class SierpTest {
    public static final int BI_WIDTH = 630;
    public static final int BI_HEIGHT = 580;
    private static final int MAX_COUNT = 100000;

    public static void main(String[] args) {

        // do this stuff off the swing event thread
        Point point1 = new Point(10, 550);
        Point point2 = new Point(300, 30);
        Point point3 = new Point(600, 555);
        Point current = point1;
        Point target = current; 
        int count = 0;

        final BufferedImage sierpImg = new BufferedImage(BI_WIDTH, BI_HEIGHT, BufferedImage.TYPE_INT_ARGB);
        Graphics g = sierpImg.getGraphics();
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, BI_WIDTH, BI_HEIGHT);
        g.setColor(Color.BLACK);

        while (count <= MAX_COUNT) {
            int choice = (int) (Math.random() * 3);
            switch (choice) {
            case 0:
                target = point1;
                break;
            case 1:
                target = point2;
                break;
            case 2:
                target = point3;
                break;
            default:
                System.exit(0);

            }
            current = midpoint(current, target);
            g.drawLine(current.x, current.y, current.x, current.y);

            count++;
        }

        // draw triangle with g here

        g.dispose(); // always dispose of any Graphics you create yourself

        // do this on the Swing event thread
        SwingUtilities.invokeLater(() -> {
            SierpPanel sierpPanel = new SierpPanel(sierpImg); // pass in image
            JFrame frame = new JFrame("Siep Frame");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(sierpPanel);
            frame.pack(); // size it to the size of the JPanel
            frame.setLocationRelativeTo(null); // center it
            frame.setVisible(true);
        });
    }

    public static Point midpoint(Point a, Point b) {
        return new Point((Math.round(a.x + b.x) / 2), (Math.round(a.y + b.y) / 2));
    }
}

class SierpPanel extends JPanel {
    private BufferedImage img = null;

    public SierpPanel(BufferedImage img) {
        this.img = img;
    }

    // so that JPanel sizes itself with the image
    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet() || img == null) {
            return super.getPreferredSize();
        }
        return new Dimension(img.getWidth(), img.getHeight());
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (img != null) {
            g.drawImage(img, 0, 0, this);
        }
    }
}

请注意,如果您想在创建三角形时获得奇特效果并延迟绘制三角形,请考虑使用 Swing Timer 或 SwingWorker。

关于java - Java Swing 中的 Sierpinski Gasket 实现仅有时出现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38668266/

相关文章:

java - jFilechooser 显示文件夹

java - 如何避免 jtable 中的指数值

java - 启用停止定时器

java - 将 cookie 传递给 GET 请求的问题(POST 之后)

Java多线程UDP服务器错误

java - 通过应用程序查询数据库的正确设计

java - JFrame 无法为多个客户端加载

java - 更改 Java 类加载器的优先级

java - 调用特定其他对象的方法

java - 为两个 JTextArea 设置事件监听器