Java Swing中的Sierpinski Gasket实现有时只会出现

时间:2016-07-29 22:19:29

标签: java swing

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

  

选择3个点来定义三角形。

     

选择其中一个顶点作为当前循环50,000次:       随机选择一个顶点作为目标。       在目标和当前之间的中点绘制一个像素。       使当前成为中点。

在下面的图片中,我有时会在编辑时得到它,但有时它会弹出并消失,或者根本不显示。如果它确实显示,然后我调整窗口大小就会消失(我不关心这个,但如果它有帮助。)我只能在编译时产生下面的图像(大约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如何处理多线程有关,但不幸的是我对如何解决它没有太多的了解。非常感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

这个循环:

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。