【问题标题】:Drawing Sierpinski's Triangle in Java在 Java 中绘制谢尔宾斯基三角形
【发布时间】:2013-05-02 07:20:00
【问题描述】:

我在绘制谢尔宾斯基三角形(或谢尔宾斯基垫片)的代码时遇到了一些问题,但我不确定问题出在哪里。绘制三角形的线,然后绘制所有分形,然后消失。帮忙?

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();
}
}

【问题讨论】:

    标签: java swing graphics geometry awt


    【解决方案1】:

    只需删除 repaint() 调用即可修复它。

    【讨论】:

      【解决方案2】:
      1. 不要从顶级容器(如JFrame)扩展,你不会为它添加任何好处。
      2. 避免在顶层容器上涂漆。而是使用JPanel 之类的东西。
      3. 避免覆盖paint,改用paintComponent。详情请见Performing Custom Painting

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

      当重绘系统决定部分或整个 UI 需要更新时,会调用 Paint 以响应许多事件。绘制具有破坏性,即调用绘制时,Graphics 将完全刷新,需要您从头开始“重建”输出。

      相反。

      编写一个递归算法,该算法可以绘制到 BufferedImage 之类的东西上,然后在 paintComponent 内绘制它...

      更新

      在 Swing 中的绘制由RepaintManager 控制,它负责确定何时以及何时重新绘制屏幕。您似乎认为paint 是您可以控制的,但实际上并非如此。

      您需要准备好完全重新绘制 UI,或者准备一个缓冲区,以便您可以根据需要在 UI 上进行绘制。

      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

      【讨论】:

      • 这对我真的没有帮助。还是谢谢。
      • 我主要关心为什么不绘制分形。
      • 您也在对单个状态或时刻做出响应。 Graphics 上下文在每个新的绘制周期中都会被清除,这意味着您之前绘制的任何内容都不再存在。您需要在每个循环中完全重建输出。当我运行你的代码时,我得到了11001 中的count,但屏幕上没有显示任何内容,因为在1001 迭代中,它被擦干净了......我确定我说过(不多说)
      • 感谢您的意见,感谢您花时间解决我的错误。需要注意的是,我是一名初级程序员,对 AWT 或 String 知之甚少。我只在我的 Java 课程中学习了 AWT 和 Swing 主题大约 3 周。在我进行此练习的 Java 教科书中,我编写此代码的方式与显示的基本相同。我的文字中没有提及您在回答中提到的一件事。我并不怀疑你的知识,但是,我想我应该像我一样解决这个问题——至少在这门课上。
      • @user2361122:如果你不介意,那本 Java 教科书叫什么名字呢?该建议至少已经过时了 10 年。
      【解决方案3】:
      int i = ((int)Math.random()*3);    
      System.out.println("i:"+i);
      

      当我运行上述代码时,我总是得到 0

      所以您的“选择”变量始终为零……可能与您的问题有关?

      【讨论】:

      • 哇!多么愚蠢的错误!这解决了它......有点。现在分形被绘制,但一旦完成就会消失。
      • 我不是挥杆专家,但是当 MadProgrammer 说“图形上下文在每个新的绘制周期都被清除干净,这意味着你以前绘制的任何东西,不再存在” - 这似乎描述了你正在发生的事情,所以我会看看他的回答:)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-01
      • 1970-01-01
      相关资源
      最近更新 更多