同时绘制分形

Paint fractals simultaneously

我需要用 Threads(实现 Runnable())为大学作业编写 java 代码。我需要同时绘制 4 个分形(使用 thread.sleep())。我已经尝试了几乎我所知道的一切,但这仍然行不通。所以我清理了源。

我有四个类(四个分形)。在我的 JPanel 中,我调用了一个 paint 方法来绘制它们(它们是递归的)。谁能救救我吗?

public class MainPanel extends JPanel {
FractalTree tree = new FractalTree();
FractalCircle circle = new FractalCircle();
FractalSquare square = new FractalSquare();
FractalCircle2 circle2 = new FractalCircle2();

@Override
public void paint(Graphics g) {
    setBackground(Color.black,g);
    Graphics2D g2 = (Graphics2D) g;
    g.setColor(Color.WHITE);
    DrawBounds(g);

    tree.drawTree(g,200,290,-90,9);
    circle.drawCircle(g2,675,175,300);
    square.drawSquares(g, 200, 525, 100,7);
    circle2.drawCircle(g2,675,518,300);
}

public void DrawBounds(Graphics g){
    g.drawLine(0,350,900,350);
    g.drawLine(450,0,450,700);
}

public void setBackground(Color c,Graphics g){
    g.fillRect(0, 0, 900, 700);
}

}

public class FractalSquare{
public void drawSquares(Graphics g,int x, int y, int side ,int size){
    g.setColor(Color.BLUE);
    if(size >2){
        size--;
        g.fillRect(x-side/2, y-side/2, side, side);  
        side = side/2;
        x = x-side;
        y = y-side;
        drawSquares(g,x,y,side,size);
        drawSquares(g,x+side*2,y,side,size);
        drawSquares(g,x,y+side*2,side,size);
        drawSquares(g,x+side*2,y+side*2,side,size);
    } else return;
}

}

public class FractalCircle {
 public void drawCircle(Graphics2D g, float x, float y, float radius) {
     g.setColor(Color.RED);
   g.draw(new Ellipse2D.Float(x-radius/2, y-radius/2, radius,radius));
    if(radius > 2) {
        radius *= 0.75f;
        drawCircle(g,x, y, radius);
    } else return ;
}

}

public class FractalCircle2 {

 public void drawCircle(Graphics2D g, float x, float y, float radius) {
   Color color = new Color(255,0,255);
   g.setColor(color);
   g.draw(new Ellipse2D.Float(x-radius/2, y-radius/2, radius,radius));
    if(radius > 1) {
        radius *= 0.75f;
        drawCircle(g,x + radius/2, y, radius/2);
        drawCircle(g,x - radius/2, y, radius/2);
    } else return ;
}

}

public class FractalTree {

public void drawTree(Graphics g, int x1, int y1, double angle, int depth) {
    g.setColor(Color.GREEN);
    if (depth == 0) return;
    int x2 = x1 + (int) (Math.cos(Math.toRadians(angle)) * depth * 5.0);
    int y2 = y1 + (int) (Math.sin(Math.toRadians(angle)) * depth * 5.0);
    g.drawLine(x1, y1, x2, y2);
    drawTree(g, x2, y2, angle - 20, depth - 1);
    drawTree(g, x2, y2, angle + 20, depth - 1);

}

}

您必须将分形渲染成单独的图像,并在渲染过程中将它们复制到屏幕上。

如果将每个分形包装在 JComponent 中,Swing 将为您完成大部分工作。

这是一个使用您的分形之一的示例:

public class FractalPanel extends JPanel {
    final FractalSquare square = new FractalSquare(450, 350);

    public FractalPanel() {
        add(square);
    }

    public static void main(String[] args) {
        FractalPanel fractalPanel = new FractalPanel();
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(fractalPanel);
        frame.pack();
        frame.setVisible(true);

        Thread squareThread = new Thread(() -> {
            try {
                fractalPanel.square.render();
            } catch (InterruptedException e) {
                System.err.println("Interrupted");
            }
        });
        squareThread.start();
    }
}

class Fractal extends JComponent {
    final BufferedImage image;
    final Graphics2D offscreenGraphics;

    public Fractal(int width, int height) {
        setPreferredSize(new Dimension(width, height));
        image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        offscreenGraphics = image.createGraphics();
    }

    // Copy the offscreen image to the main graphics context
    @Override
    public void paint(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        synchronized (image) { // synchronize with the render thread
            g2.drawImage(image, 0, 0, null);
        }
    }
}

class FractalSquare extends Fractal {
    public FractalSquare(int width, int height) {
        super(width, height);
    }

    public void render() throws InterruptedException {
        drawSquares(getWidth() / 2, getHeight() / 2, 100, 7);
    }

    public void drawSquares(int x, int y, int side, int size) throws InterruptedException {

        // Sleep for 10ms between frames
        Thread.sleep(10);

        if (size > 2) {
            size--;

            synchronized (image) { // synchronize with the draw thread
                offscreenGraphics.setColor(Color.BLUE);
                System.out.printf("Filling [%d, %d, %d, %d]\n", x - side / 2, y - side / 2, side, side);
                offscreenGraphics.fillRect(x - side / 2, y - side / 2, side, side);
            }

            // Tell Swing that we've updated the image and it needs to be redrawn
            repaint();

            side = side / 2;
            x = x - side;
            y = y - side;
            drawSquares(x, y, side, size);
            drawSquares(x + side * 2, y, side, size);
            drawSquares(x, y + side * 2, side, size);
            drawSquares(x + side * 2, y + side * 2, side, size);
        }
    }
}

在包含您的 MainPanelJFrame 中,添加此代码(私有 Thread 及其构造函数中某处的实例):

private Thread threadRepaint;

...

threadRepaint = new Thread(new Runnable() {
    @Override
    public void run() {
        while (true) {
            try {
                yourPanel.repaint();

                FractalSquare.decreaseLimit();
                FractalCircle.decreaseLimit();
                FractalCircle2.decreaseLimit();
                FractalTree.decreaseLimit();

                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
});

threadRepaint.start();

这背后的想法是线程必须每秒(1000 毫秒)减少分形的限制。

在每个分形 类 中,您必须将条件更改为类似这样的内容,并添加一个静态变量。这样,您将看到每次迭代的进展。

对于你的FractalSquare,它会在到达 2:

时停止
private static limit = 10;

...

public static void decreaseLimit() {
    if (limit > 2) limit--;
}

...
    // Inside your drawSquares method

    if (size > limit){
        ...
    } else return;

其他每个分形的想法基本相同:您设置一个上限,该上限会随着时间(线程的每次迭代)而减小。递减限制会产生每次迭代都在递增的错觉。