繁体   English   中英

带有 Java Swing 的 Mutli Threaded Mandelbrot Set 查看器

[英]Mutli Threaded Mandelbrot Set viewer with Java Swing

在 Java 中尝试使用 Swing 图形的多线程 Mandelbrot 集查看器。 我见过一些使用 BufferedImage 和/或 SwingWorker 的 Mandelbrot Set 程序和其他多线程 Swing 应用程序,但我想知道这种方法是否可以工作/被赎回,如果不能,为什么不呢?

在单击(放大)和按键(缩小)时,我正在打开线程以计算象限中的颜色值(左上、右上、左下、右下),并在private static Color[][] colors = new Color[n][n]; . 然后在组件上调用repaint方法从colors数组中进行绘制。

这些线程是否与 Event Dispatch Thread 并发执行,如果是,为什么这些线程不发生在 Event Dispatch Thread Swing 组件绘制之前,并带有SwingUtilities.invokeLater

没有错误消息,只是在单击和按键时出现不可预测的重绘行为。 谢谢你。

曼德布洛特.java

import java.awt.Color;
import java.awt.BorderLayout;
import java.awt.Graphics;
import javax.swing.SwingUtilities;
import javax.swing.JFrame;
import javax.swing.JPanel;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Stack;

public class Mandelbrot extends JPanel {
    private static double size = 4.0; // complex plane is size units in width and length
    private static int n    = 1000; // window is n x n in pixels
    private static int max  = 255; // iterate through hex color values
    private static double x0 = -size/2; // set window origin
    private static double y0 = size/2; // set window origin
    private static double xC = 0; // set complex plane origin
    private static double yC = 0; // set complex plane origin
    private static double scaleFactor = size/n; // translate complex plane to pixels
    private static Stack<double[]> origins = new Stack<double[]>(); // track origins for zooming out
    private static double zoom = 2.0; // modify to alter brightness scheme on zoom
    private static Color[][] colors = new Color[n][n];

    public Mandlebrot() {
        addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                double[] center = new double[]{xC, yC}; // rescale
                origins.push(center);
                zoom = (zoom * 2) - (0.5 * zoom);
                xC = x0 + (scaleFactor * e.getX());
                yC = y0 - (scaleFactor * e.getY());
                size = size/2.0;
                scaleFactor = size/n;
                x0 = xC - (size/2);
                y0 = yC + (size/2);
                ComputeThread quadrant1 = new ComputeThread(n, zoom, x0, y0, 0, n/2, 0, n/2, max, scaleFactor, colors);
                ComputeThread quadrant2 = new ComputeThread(n, zoom, x0, y0, n/2, n, 0, n/2, max, scaleFactor, colors);
                ComputeThread quadrant3 = new ComputeThread(n, zoom, x0, y0, 0, n/2, n/2, n, max, scaleFactor, colors);
                ComputeThread quadrant4 = new ComputeThread(n, zoom, x0, y0, n/2, n, n/2, n, max, scaleFactor, colors);
                Thread thread1 = new Thread(quadrant1);
                Thread thread2 = new Thread(quadrant2);
                Thread thread3 = new Thread(quadrant3);
                Thread thread4 = new Thread(quadrant4);
                thread1.start();
                thread2.start();
                thread3.start();
                thread4.start();
                repaint(0, 0, getWidth(), getHeight());
            }
        });
        addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_LEFT) {
                    double[] center = origins.pop(); // rescale
                    zoom = (zoom + (zoom / 3)) / 2;
                    xC = center[0];
                    yC = center[1];
                    size = size*2.0;
                    scaleFactor = size/n;
                    x0 = xC - (size/2);
                    y0 = yC + (size/2);
                    ComputeThread quadrant1 = new ComputeThread(n, zoom, x0, y0, 0, n/2, 0, n/2, max, scaleFactor, colors);
                    ComputeThread quadrant2 = new ComputeThread(n, zoom, x0, y0, n/2, n, 0, n/2, max, scaleFactor, colors);
                    ComputeThread quadrant3 = new ComputeThread(n, zoom, x0, y0, 0, n/2, n/2, n, max, scaleFactor, colors);
                    ComputeThread quadrant4 = new ComputeThread(n, zoom, x0, y0, n/2, n, n/2, n, max, scaleFactor, colors);
                    Thread thread1 = new Thread(quadrant1);
                    Thread thread2 = new Thread(quadrant2);
                    Thread thread3 = new Thread(quadrant3);
                    Thread thread4 = new Thread(quadrant4);
                    thread1.start();
                    thread2.start();
                    thread3.start();
                    thread4.start();
                    repaint(0, 0, getWidth(), getHeight());
                }
            }
        });
    }
    
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {           
                g.setColor(colors[j][i]);
                g.drawLine(i, j, i, j);
            }
        }
    }

    public static int mand(Complex z0, int max) {
        Complex z = z0;
        for (int t = 0; t < max; t++) {
            if (z.abs() > zoom) {
                return t;
            }
            z = Complex.ad(Complex.mult(z, z), z0);
        }
        return max;
    }
    
    
    public static void main(String[] args) {

        
        for (int i = 0; i < n; i++) { // initialize array for initial drawing
            for (int j = 0; j < n; j++) {
                double a = x0 + (i * scaleFactor);
                double b = y0 - (j * scaleFactor);
                Complex z0 = new Complex(a, b);
                int gray = max - mand(z0, max);
                Color color = new Color(gray, gray, gray);
                colors[j][i] = color;
            }
        }

        
        SwingUtilities.invokeLater(() -> {
            var panel = new Threading();
            panel.setBackground(Color.WHITE);
            panel.setFocusable(true);
            var frame = new JFrame("Mandelbrot");
            frame.setSize(n, n);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(panel, BorderLayout.CENTER);
            frame.setVisible(true);
        });
        
    }

}

ComputeThread.java

import java.awt.Color;

public class ComputeThread implements Runnable {
    
    private static int n;
    private static double x0;
    private static double y0;
    private static int xLow;
    private static int xHigh;
    private static int yLow;
    private static int yHigh;
    private static int max;
    private static double scaleFactor;
    private static double zoom;
    private static Color[][] colors = new Color[1000][1000];
    
    public ComputeThread(int n, double zoom, double x0, double y0, int xLow, int xHigh, int yLow, int yHigh, int max, double scaleFactor, Color[][] colors) {
        this.n = n;
        this.zoom = zoom;
        this.x0 = x0;
        this.y0 = y0;
        this.xLow = xLow;
        this.xHigh = xHigh;
        this.yLow = yLow;
        this.yHigh = yHigh;
        this.max = max;
        this.scaleFactor = scaleFactor;
        this.colors = colors;
    }

    @Override
    public void run() {
        for (int i = xLow; i < xHigh; i++) {
            for (int j = yLow; j < yHigh; j++) {
                double a = x0 + (i * scaleFactor);
                double b = y0 - (j * scaleFactor);
                Complex z0 = new Complex(a, b);
                int gray = max - mand(z0, max);
                Color color = new Color(gray, gray, gray);
                colors[j][i] = color;
            }
        }
    }

    public static int mand(Complex z0, int max) {
        Complex z = z0;
        for (int t = 0; t < max; t++) {
            if (z.abs() > zoom) {
                return t;
            }
            z = Complex.ad(Complex.mult(z, z), z0);
        }
        return max;
    }
    
}

复合物.java

import java.lang.Math;

public class Complex {
    double real;
    double imag;
    public Complex(double real, double imag) {
        this.real = real;
        this.imag = imag;
    }
    public static Complex ad(Complex num1, Complex num2) {
        Complex num = new Complex(0.0, 0.0);
        num.real = num1.real + num2.real;
        num.imag = num1.imag + num2.imag;
        return(num);
    }
    
    public static Complex mult(Complex num1, Complex num2) {
        Complex num = new Complex(0.0, 0.0);
        num.real = num1.real * num2.real - num1.imag * num2.imag;
        num.imag = num1.real * num2.imag + num1.imag * num2.real;
        return(num);
    }
    
    public double abs() {
        return Math.hypot(real, imag);
    }
}
  1. 您在 ComputeThread 中使用 static 字段时犯了一个错误。 这样线程使用相同的 arrays 并且它们相互覆盖。 所以你得到了 1/4 的图像。

  2. 重绘与线程同时运行,因此如果它更早完成,则不会绘制整个图像。 您必须通知 JFrame 完成的计算,以便在一切准备就绪后重新绘制。

在效果更好的代码下方:

曼德布洛特.java

package mb;

import java.awt.Color;
import java.awt.BorderLayout;
import java.awt.Graphics;
import javax.swing.SwingUtilities;
import javax.swing.JFrame;
import javax.swing.JPanel;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.EventListener;
import java.util.Stack;

public class Mandelbrot extends JPanel implements CalcListener {
    private static double size = 4.0; // complex plane is size units in width and length
    private static int n    = 1000; // window is n x n in pixels
    private static int max  = 255; // iterate through hex color values
    private static double x0 = -size/2; // set window origin
    private static double y0 = size/2; // set window origin
    private static double xC = 0; // set complex plane origin
    private static double yC = 0; // set complex plane origin
    private static double scaleFactor = size/n; // translate complex plane to pixels
    private static Stack<double[]> origins = new Stack<double[]>(); // track origins for zooming out
    private static double zoom = 2.0; // modify to alter brightness scheme on zoom
    private static Color[][] colors = new Color[n][n];
    static Mandelbrot me;

    public Mandelbrot() {
        this.me=this;
        addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                double[] center = new double[]{xC, yC}; // rescale
                origins.push(center);
                zoom = (zoom * 2) - (0.5 * zoom);
                xC = x0 + (scaleFactor * e.getX());
                yC = y0 - (scaleFactor * e.getY());
                size = size/2.0;
                scaleFactor = size/n;
                x0 = xC - (size/2);
                y0 = yC + (size/2);
                ComputeThread quadrant1 = new ComputeThread(n, zoom, x0, y0, 0, n/2, 0, n/2, max, scaleFactor, colors, me);
                ComputeThread quadrant2 = new ComputeThread(n, zoom, x0, y0, n/2, n, 0, n/2, max, scaleFactor, colors, me);
                ComputeThread quadrant3 = new ComputeThread(n, zoom, x0, y0, 0, n/2, n/2, n, max, scaleFactor, colors, me);
                ComputeThread quadrant4 = new ComputeThread(n, zoom, x0, y0, n/2, n, n/2, n, max, scaleFactor, colors, me);
                Thread thread1 = new Thread(quadrant1);
                Thread thread2 = new Thread(quadrant2);
                Thread thread3 = new Thread(quadrant3);
                Thread thread4 = new Thread(quadrant4);
                thread1.start();
                thread2.start();
                thread3.start();
                thread4.start();
                repaint(0, 0, getWidth(), getHeight());
            }
        });
        addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_LEFT) {
                    double[] center = origins.pop(); // rescale
                    zoom = (zoom + (zoom / 3)) / 2;
                    xC = center[0];
                    yC = center[1];
                    size = size*2.0;
                    scaleFactor = size/n;
                    x0 = xC - (size/2);
                    y0 = yC + (size/2);
                    ComputeThread quadrant1 = new ComputeThread(n, zoom, x0, y0, 0, n/2, 0, n/2, max, scaleFactor, colors,me);
                    ComputeThread quadrant2 = new ComputeThread(n, zoom, x0, y0, n/2, n, 0, n/2, max, scaleFactor, colors,me);
                    ComputeThread quadrant3 = new ComputeThread(n, zoom, x0, y0, 0, n/2, n/2, n, max, scaleFactor, colors,me);
                    ComputeThread quadrant4 = new ComputeThread(n, zoom, x0, y0, n/2, n, n/2, n, max, scaleFactor, colors,me);
                    Thread thread1 = new Thread(quadrant1);
                    Thread thread2 = new Thread(quadrant2);
                    Thread thread3 = new Thread(quadrant3);
                    Thread thread4 = new Thread(quadrant4);
                    thread1.start();
                    thread2.start();
                    thread3.start();
                    thread4.start();
                    repaint(0, 0, getWidth(), getHeight());
                }
            }
        });
    }
    
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {           
                g.setColor(colors[j][i]);
                g.drawLine(i, j, i, j);
            }
        }
    }

    public static int mand(Complex z0, int max) {
        Complex z = z0;
        for (int t = 0; t < max; t++) {
            if (z.abs() > zoom) {
                return t;
            }
            z = Complex.ad(Complex.mult(z, z), z0);
        }
        return max;
    }
    
    
    public static void main(String[] args) {

        
        for (int i = 0; i < n; i++) { // initialize array for initial drawing
            for (int j = 0; j < n; j++) {
                double a = x0 + (i * scaleFactor);
                double b = y0 - (j * scaleFactor);
                Complex z0 = new Complex(a, b);
                int gray = max - mand(z0, max);
                Color color = new Color(gray, gray, gray);
                colors[j][i] = color;
            }
        }

        
        SwingUtilities.invokeLater(() -> {
            var panel = new Mandelbrot();
            panel.setBackground(Color.WHITE);
            panel.setFocusable(true);
            var frame = new JFrame("Mandelbrot");
            frame.setSize(n, n);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(panel, BorderLayout.CENTER);
            frame.setVisible(true);
        });
        
    }
    
    public void calcDoneEvent()  
    {
      repaint();
    }
}

ComputeThread.java

package mb;

import java.awt.Color;

public class ComputeThread implements Runnable {
    
    private  int n;
    private  double x0;
    private  double y0;
    private  int xLow;
    private  int xHigh;
    private  int yLow;
    private  int yHigh;
    private  int max;
    private  double scaleFactor;
    private  double zoom;
    private  Color[][] colors = new Color[1000][1000];
    private CalcListener listener;
    
    public ComputeThread(int n, double zoom, double x0, double y0, int xLow, int xHigh, int yLow, int yHigh, int max, double scaleFactor, Color[][] colors,CalcListener l) {
        this.n = n;
        this.zoom = zoom;
        this.x0 = x0;
        this.y0 = y0;
        this.xLow = xLow;
        this.xHigh = xHigh;
        this.yLow = yLow;
        this.yHigh = yHigh;
        this.max = max;
        this.scaleFactor = scaleFactor;
        this.colors = colors;
        this.listener = l;
    }

    @Override
    public void run() {
        for (int i = xLow; i < xHigh; i++) {
            for (int j = yLow; j < yHigh; j++) {
                double a = x0 + (i * scaleFactor);
                double b = y0 - (j * scaleFactor);
                Complex z0 = new Complex(a, b);
                int gray = max - mand(z0, max);
                Color color = new Color(gray, gray, gray);
                colors[j][i] = color;
            }
        }
        listener.calcDoneEvent();
    }

    public  int mand(Complex z0, int max) {
        Complex z = z0;
        for (int t = 0; t < max; t++) {
            if (z.abs() > zoom) {
                return t;
            }
            z = Complex.ad(Complex.mult(z, z), z0);
        }
        return max;
    }
    
}

CalcListener.java

package mb;

public interface CalcListener
{
  public void calcDoneEvent();
}

并且 Complex.java 没有修改。

另一个问题是编码风格。 我通过在 Mandelbrot 中放置 static“me”变量来创建捷径,这是不好的做法。 正确地,您应该继承鼠标和键适配器以拥有能够将侦听器传递给线程的类。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM