java - 在 Java 中绘制谢尔宾斯基三角形

标签 java swing graphics geometry awt

我在绘制 Sierpinski 三角形(或 Sierpinski 垫圈)的代码中遇到了一些问题,但我不确定问题出在哪里。绘制三角形的线,然后绘制所有分形,然后它消失。帮忙?

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

public class SierpinskiGasket extends JFrame {

Point x=new Point(5,545),
      y=new Point(300,25),
      z=new Point(605,545),
      current=x, target;
private int count=0;

public SierpinskiGasket () {
    super("Sierpinski Gasket");
    setSize(610,550);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    getContentPane().setBackground(Color.WHITE);
    setLocationRelativeTo(null);
    setResizable(false);
    setVisible(true);
}

public void paint(Graphics g) {
    super.paint(g);
    if(count==0) {
    g.drawLine(x.x,x.y,y.x,y.y);
    g.drawLine(x.x,x.y,z.x,z.y);
    g.drawLine(z.x,z.y,y.x,y.y);
    } else {
        while(count<10000) {
            int choice=(int)(Math.random()*3);
            switch(choice) {
                case 0: target=x; break;
                case 1: target=y; break;
                case 2: target=z; break;
                default: System.exit(0);
            }
            current=midpoint(current,target);
            g.drawRect(current.x,current.y,5,5);
            repaint();
            count++;
        }
    }
    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));
}

public static void main(String[] args) {
    new SierpinskiGasket();
}
}

最佳答案

  1. 不要从顶级容器(如 JFrame)扩展,您不会向它添加任何好处。
  2. 避免绘制到顶层容器。而是使用类似 JPanel 的东西。
  3. 避免覆盖 paint,而是使用 paintComponent。参见 Performing Custom Painting了解更多详情

这不是 paint 的工作方式(我不会尝试重写您的代码来实现它)。

当重绘系统决定部分或整个 UI 需要更新时,调用 Paint 以响应许多事件。绘制是破坏性的,也就是说,当调用绘制时,Graphics 将被完全刷新,需要您从头“重建”输出。

相反。

编写一个递归算法,可以绘制类似 BufferedImage 的东西,并在 paintComponent 中绘制...

已更新

Swing 中的绘制由 RepaintManager 控制,它负责确定重绘屏幕的内容和时间。您似乎认为 paint 是您可以控制的东西,但事实并非如此。

您需要准备好完全重新绘制 UI,或者准备好可以在 UI 上绘制的缓冲区,具体取决于您的需要。

enter image description here

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class SierpinskisGasket {

    public static void main(String[] args) {
        new SierpinskisGasket();
    }

    public SierpinskisGasket() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            BaseShape base = new BaseShape(Math.min(getWidth(), getHeight()));
            Rectangle bounds = base.getBounds();
            int x = (getWidth() - bounds.width) / 2;
            int y = (getHeight() - bounds.height) / 2;
            base.transform(AffineTransform.getTranslateInstance(x, y));
            g2d.fill(base);
            g2d.dispose();
        }
    }

    public class BaseShape extends Path2D.Float {

        public BaseShape(float size) {

            float subSize = size / 2f;
            Triangle top = new Triangle(subSize);
            top.transform(AffineTransform.getTranslateInstance((size - subSize) / 2, 0));
            append(top, false);

            Triangle left = new Triangle(subSize);
            left.transform(AffineTransform.getTranslateInstance(0, subSize));
            append(left, false);

            Triangle right = new Triangle(subSize);
            right.transform(AffineTransform.getTranslateInstance(subSize, subSize));
            append(right, false);

        }

    }

    public class Triangle extends Path2D.Float {

        public Triangle(float size) {

            moveTo(size / 2f, 0);
            lineTo(size, size);
            lineTo(0, size);
            closePath();

        }

    }

}

你永远不应该从 paint 调用任何可能改变 UI 状态并触发另一个 repaint 的东西,否则你将进入一个结束循环最终会消耗您的 CPU 的重绘。

您还应该看看 Painting in AWT and Swing

关于java - 在 Java 中绘制谢尔宾斯基三角形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16434273/

相关文章:

java - 尝试从文本文件中读取

java - 当 O(1) 与 O(log n) 无关紧要时,TreeSet 与 HashSet 对于小集合大小的速度

java - 错误: Could not find or load main class Maven Spring Boot Application - Executable JAR

java - 如何在同一台显示器上打开一个帧并在 swing 中打开另一个帧?

java - 带有单选按钮的 JFrame 布局

java - 将 Wav 文件转换为 Java - 特定格式

java - 如何监听窗口大小更改事件

ruby-on-rails - Ruby 程序员与图形设计师的协作 : Best practices?

java - java中绘制图像时jFrame GetGraphics为空

java - Slick2D 加载图像不起作用