Java 更改BuffereImage的内容,然后更新JFrame以反映它

Java 更改BuffereImage的内容,然后更新JFrame以反映它,java,swing,jframe,bufferedimage,mandelbrot,Java,Swing,Jframe,Bufferedimage,Mandelbrot,我正在尝试制作一个带有GUI的Mandelbrot集渲染器,您可以在其中单击并拖动以放大到特定区域。运行时,它将进行初始计算并进行精细渲染,但当您尝试单击并拖动以放大时,控制台会说它正在进行计算,但JFrame的内容不会更新 但是,我甚至不确定它是否正在重新计算,因为初始计算大约需要8秒,但当您单击/拖动缩放时,大约需要6毫秒 我已经在下面发布了我的代码 复数类 public class Complex { private double real, imag; // Const

我正在尝试制作一个带有GUI的Mandelbrot集渲染器,您可以在其中单击并拖动以放大到特定区域。运行时,它将进行初始计算并进行精细渲染,但当您尝试单击并拖动以放大时,控制台会说它正在进行计算,但JFrame的内容不会更新

但是,我甚至不确定它是否正在重新计算,因为初始计算大约需要8秒,但当您单击/拖动缩放时,大约需要6毫秒

我已经在下面发布了我的代码

复数类

public class Complex {
    private double real, imag;

    // Constructors
    public Complex(){
        real=0.0;
        imag=0.0;
    }

    public Complex(double real, double imag) {
        this.real=real;
        this.imag=imag;
    }

    // add given complex number to this one, returning the Complex result
    public Complex add(Complex other) {
        return new Complex(this.real+other.real, this.imag+other.imag);
    }

    // multiply given complex number by this one, returning the Complex result
    public Complex multiply(Complex other) {
        return new Complex((this.real*other.real)-(this.imag*other.imag), (this.imag*other.real)+(this.real*other.imag));
    }

    // get the magnitude of this complex number
    public double getMagnitude() {
        return Math.sqrt((real*real)+(imag*imag));
    }
}
public class MandelbrotTask implements Runnable {
    private double x1, y1, x2, y2;
    private int startCol, endCol, startRow, endRow, maxIters;
    private int[][] iterCounts;

       public MandelbrotTask(int maxIters, double x1, double y1, double x2, double y2, int startCol, int endCol, int startRow, int endRow, int[][] iterCounts) {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
            this.startCol = startCol;
            this.endCol = endCol;
            this.startRow = startRow;
            this.endRow = endRow;
            this.iterCounts = iterCounts;
            this.maxIters=maxIters;         
}

    @Override
    public void run() {
        for (int i = startRow; i < endRow; i++) {
            for (int j = startCol; j < endCol; j++) {
                Complex c = getComplex(i, j);
                int iterCount = countIters(c);
                iterCounts[i][j] = iterCount;
            }
        }
    }

    public Complex getComplex(int i, int j){
        //output image is 600 X 600 pixels
        double incrementX;
        double incrementY;
        if(x2!=x1){
            incrementX=(Math.abs(x2-x1)/600);
        }
        else{
            throw new ArithmeticException("Error: area=0");
        }
        if(y2!=y1){
            incrementY=(Math.abs(y2-y1)/600);
        }
        else{
            throw new ArithmeticException("Error: area=0");
        }

        return new Complex(x1+((double)i*incrementX), y1+((double)j*incrementY));
    }

    public int countIters(Complex c){
        Complex z=new Complex(0, 0);
        int iters=0;
        while(z.getMagnitude()<2 && iters<=maxIters){
            z=z.multiply(z).add(c);
            iters++;
        }
        return iters;
    }
}
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Scanner;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class Mandelbrot {
    private static final int HEIGHT = 600;
    private static final int WIDTH = 600;
    private static final int maxIters=50000;

    private static Rectangle zoomBox;
    private static Point initialClick;
    private static JLabel content; //bufferedImage will be put into this JLabel
    private static int[][] iterCounts;
    private static BufferedImage bufferedImage; //rendering will be written to this bufferedImage
    private static JFrame frame;

    public static void main(String[] args) throws IOException {
        zoomBox=null;
        Scanner keyboard = new Scanner(System.in);

        double x1 = -2;
        double y1 = -2;
        double x2 = 2;
        double y2 = 2;
        /*System.out.print("Max iterations (16,581,375 supported): ");
        int maxIters=50000;
        if(maxIters>16581375){
            throw new UnsupportedOperationException("Error: Max Iterations: Overflow.");
        }
        System.out.print("Output filename: ");
        String fileName = keyboard.next();
        if(!fileName.endsWith(".png") && !fileName.endsWith(".PNG")){
            fileName=fileName + ".png";
        }*/

        // TODO: create the rendering, save it to a file
        iterCounts=new int[WIDTH][HEIGHT];
        recalculate(x1, y1, x2, y2, iterCounts);

        bufferedImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
        MouseAdapter listener = new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                handleMousePressed(e);
            }

            @Override
            public void mouseDragged(MouseEvent e) {
                handleMouseDragged(e);
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                handleMouseReleased(e);
            }
        };
        content=new JLabel(new ImageIcon(render(iterCounts, bufferedImage, zoomBox, true)));
        content.addMouseListener(listener);
        content.addMouseMotionListener(listener);

        /*OutputStream os = new BufferedOutputStream(new FileOutputStream(fileName));
        try {
            ImageIO.write(bufferedImage, "PNG", os);
        } finally {
            os.close();
        }*/


        frame = new JFrame("Mandelbrot Viewer");
        frame.getContentPane().add(content);
        frame.pack();
        frame.setSize(new Dimension(WIDTH, HEIGHT));
        frame.setResizable(false);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    public static BufferedImage render(int[][] iterCounts, BufferedImage bufferedImage, Rectangle zoomBox, boolean updated){
        bufferedImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
        Graphics g = bufferedImage.getGraphics();
        Graphics2D g2=(Graphics2D) g;
        if(updated){
            for(int i=0; i<WIDTH; i++){
                for(int j=0; j<HEIGHT; j++){
                    if(iterCounts[i][j]<maxIters){
                        String hexCode= String.format("#%06x", (0xFFFFFF & (32*iterCounts[i][j])));
                        g.setColor(Color.decode(hexCode));
                    }
                    else{
                        g.setColor(Color.CYAN);
                    }
                    g.drawLine(i, j, i, j);
                }
            }
        }
        else{
            if(zoomBox!=null){
                g2.setStroke(new BasicStroke(7));
                g2.draw(zoomBox);
            }
        }

        return bufferedImage;
    }

    public static int[][] recalculate(double x1, double y1, double x2, double y2, int[][] iterCounts){
        MandelbrotTask[] tasks=new MandelbrotTask[4];
        tasks[0]=new MandelbrotTask(maxIters, x1, y1, x2, y2, 0, WIDTH, 0, HEIGHT/4, iterCounts);
        tasks[1]=new MandelbrotTask(maxIters, x1, y1, x2, y2, 0, WIDTH, HEIGHT/4, 2*(HEIGHT/4), iterCounts);
        tasks[2]=new MandelbrotTask(maxIters, x1, y1, x2, y2, 0, WIDTH, 2*(HEIGHT/4), 3*(HEIGHT/4), iterCounts);
        tasks[3]=new MandelbrotTask(maxIters, x1, y1, x2, y2, 0, WIDTH, 3*(HEIGHT/4), 4*(HEIGHT/4), iterCounts);
        //parallelize computation
        Thread[] threads=new Thread[4];
        for(int i=0; i<4; i++){
            threads[i]=new Thread(tasks[i]);
        }

        System.out.println("Working...");
        //start timer, start computation
        long start=System.currentTimeMillis();
        for(int i=0; i<4; i++){
            threads[i].start();
        }

        for(int i=0; i<4; i++){
            try {
                threads[i].join();
            } catch (InterruptedException e) {
                System.err.println("A thread was interrupted.");
            }
        }
        //end timer
        long end=System.currentTimeMillis();
        long elapsed=end-start;
        System.out.println("Done.");
        System.out.println("Took " + elapsed + " ms.");

        return iterCounts;
    }

    protected static void handleMousePressed(MouseEvent e) {
        initialClick=e.getPoint();
    }

    protected static void handleMouseDragged(MouseEvent e) {
        if(e.getX()>e.getY()){
            zoomBox=new Rectangle((int)initialClick.getX(), (int)initialClick.getY(), (int)(e.getX()-initialClick.getX()), (int)(e.getY()-initialClick.getX()));
        }
        else if(e.getY()>e.getX()){
            zoomBox=new Rectangle((int)initialClick.getX(), (int)initialClick.getY(), (int)(e.getX()-initialClick.getY()), (int)(e.getY()-initialClick.getY()));
        }
        else{
            zoomBox=new Rectangle((int)initialClick.getX(), (int)initialClick.getY(), (int)(e.getX()-initialClick.getX()), (int)(e.getY()-initialClick.getY()));
        }
        content=new JLabel(new ImageIcon(render(iterCounts, bufferedImage, zoomBox, false)));
        content.repaint();
    }

    protected static void handleMouseReleased(MouseEvent e) {
        recalculate(initialClick.getX(), initialClick.getY(), e.getX(), e.getY(), iterCounts);
        SwingUtilities.invokeLater(new Runnable(){
            @Override
            public void run() {
                zoomBox=null;
                content=new JLabel(new ImageIcon(render(iterCounts, bufferedImage, zoomBox, false)));
                content.repaint();
            }
        });
    }
}
可运行的MandelbrotTask类

public class Complex {
    private double real, imag;

    // Constructors
    public Complex(){
        real=0.0;
        imag=0.0;
    }

    public Complex(double real, double imag) {
        this.real=real;
        this.imag=imag;
    }

    // add given complex number to this one, returning the Complex result
    public Complex add(Complex other) {
        return new Complex(this.real+other.real, this.imag+other.imag);
    }

    // multiply given complex number by this one, returning the Complex result
    public Complex multiply(Complex other) {
        return new Complex((this.real*other.real)-(this.imag*other.imag), (this.imag*other.real)+(this.real*other.imag));
    }

    // get the magnitude of this complex number
    public double getMagnitude() {
        return Math.sqrt((real*real)+(imag*imag));
    }
}
public class MandelbrotTask implements Runnable {
    private double x1, y1, x2, y2;
    private int startCol, endCol, startRow, endRow, maxIters;
    private int[][] iterCounts;

       public MandelbrotTask(int maxIters, double x1, double y1, double x2, double y2, int startCol, int endCol, int startRow, int endRow, int[][] iterCounts) {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
            this.startCol = startCol;
            this.endCol = endCol;
            this.startRow = startRow;
            this.endRow = endRow;
            this.iterCounts = iterCounts;
            this.maxIters=maxIters;         
}

    @Override
    public void run() {
        for (int i = startRow; i < endRow; i++) {
            for (int j = startCol; j < endCol; j++) {
                Complex c = getComplex(i, j);
                int iterCount = countIters(c);
                iterCounts[i][j] = iterCount;
            }
        }
    }

    public Complex getComplex(int i, int j){
        //output image is 600 X 600 pixels
        double incrementX;
        double incrementY;
        if(x2!=x1){
            incrementX=(Math.abs(x2-x1)/600);
        }
        else{
            throw new ArithmeticException("Error: area=0");
        }
        if(y2!=y1){
            incrementY=(Math.abs(y2-y1)/600);
        }
        else{
            throw new ArithmeticException("Error: area=0");
        }

        return new Complex(x1+((double)i*incrementX), y1+((double)j*incrementY));
    }

    public int countIters(Complex c){
        Complex z=new Complex(0, 0);
        int iters=0;
        while(z.getMagnitude()<2 && iters<=maxIters){
            z=z.multiply(z).add(c);
            iters++;
        }
        return iters;
    }
}
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Scanner;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class Mandelbrot {
    private static final int HEIGHT = 600;
    private static final int WIDTH = 600;
    private static final int maxIters=50000;

    private static Rectangle zoomBox;
    private static Point initialClick;
    private static JLabel content; //bufferedImage will be put into this JLabel
    private static int[][] iterCounts;
    private static BufferedImage bufferedImage; //rendering will be written to this bufferedImage
    private static JFrame frame;

    public static void main(String[] args) throws IOException {
        zoomBox=null;
        Scanner keyboard = new Scanner(System.in);

        double x1 = -2;
        double y1 = -2;
        double x2 = 2;
        double y2 = 2;
        /*System.out.print("Max iterations (16,581,375 supported): ");
        int maxIters=50000;
        if(maxIters>16581375){
            throw new UnsupportedOperationException("Error: Max Iterations: Overflow.");
        }
        System.out.print("Output filename: ");
        String fileName = keyboard.next();
        if(!fileName.endsWith(".png") && !fileName.endsWith(".PNG")){
            fileName=fileName + ".png";
        }*/

        // TODO: create the rendering, save it to a file
        iterCounts=new int[WIDTH][HEIGHT];
        recalculate(x1, y1, x2, y2, iterCounts);

        bufferedImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
        MouseAdapter listener = new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                handleMousePressed(e);
            }

            @Override
            public void mouseDragged(MouseEvent e) {
                handleMouseDragged(e);
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                handleMouseReleased(e);
            }
        };
        content=new JLabel(new ImageIcon(render(iterCounts, bufferedImage, zoomBox, true)));
        content.addMouseListener(listener);
        content.addMouseMotionListener(listener);

        /*OutputStream os = new BufferedOutputStream(new FileOutputStream(fileName));
        try {
            ImageIO.write(bufferedImage, "PNG", os);
        } finally {
            os.close();
        }*/


        frame = new JFrame("Mandelbrot Viewer");
        frame.getContentPane().add(content);
        frame.pack();
        frame.setSize(new Dimension(WIDTH, HEIGHT));
        frame.setResizable(false);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    public static BufferedImage render(int[][] iterCounts, BufferedImage bufferedImage, Rectangle zoomBox, boolean updated){
        bufferedImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
        Graphics g = bufferedImage.getGraphics();
        Graphics2D g2=(Graphics2D) g;
        if(updated){
            for(int i=0; i<WIDTH; i++){
                for(int j=0; j<HEIGHT; j++){
                    if(iterCounts[i][j]<maxIters){
                        String hexCode= String.format("#%06x", (0xFFFFFF & (32*iterCounts[i][j])));
                        g.setColor(Color.decode(hexCode));
                    }
                    else{
                        g.setColor(Color.CYAN);
                    }
                    g.drawLine(i, j, i, j);
                }
            }
        }
        else{
            if(zoomBox!=null){
                g2.setStroke(new BasicStroke(7));
                g2.draw(zoomBox);
            }
        }

        return bufferedImage;
    }

    public static int[][] recalculate(double x1, double y1, double x2, double y2, int[][] iterCounts){
        MandelbrotTask[] tasks=new MandelbrotTask[4];
        tasks[0]=new MandelbrotTask(maxIters, x1, y1, x2, y2, 0, WIDTH, 0, HEIGHT/4, iterCounts);
        tasks[1]=new MandelbrotTask(maxIters, x1, y1, x2, y2, 0, WIDTH, HEIGHT/4, 2*(HEIGHT/4), iterCounts);
        tasks[2]=new MandelbrotTask(maxIters, x1, y1, x2, y2, 0, WIDTH, 2*(HEIGHT/4), 3*(HEIGHT/4), iterCounts);
        tasks[3]=new MandelbrotTask(maxIters, x1, y1, x2, y2, 0, WIDTH, 3*(HEIGHT/4), 4*(HEIGHT/4), iterCounts);
        //parallelize computation
        Thread[] threads=new Thread[4];
        for(int i=0; i<4; i++){
            threads[i]=new Thread(tasks[i]);
        }

        System.out.println("Working...");
        //start timer, start computation
        long start=System.currentTimeMillis();
        for(int i=0; i<4; i++){
            threads[i].start();
        }

        for(int i=0; i<4; i++){
            try {
                threads[i].join();
            } catch (InterruptedException e) {
                System.err.println("A thread was interrupted.");
            }
        }
        //end timer
        long end=System.currentTimeMillis();
        long elapsed=end-start;
        System.out.println("Done.");
        System.out.println("Took " + elapsed + " ms.");

        return iterCounts;
    }

    protected static void handleMousePressed(MouseEvent e) {
        initialClick=e.getPoint();
    }

    protected static void handleMouseDragged(MouseEvent e) {
        if(e.getX()>e.getY()){
            zoomBox=new Rectangle((int)initialClick.getX(), (int)initialClick.getY(), (int)(e.getX()-initialClick.getX()), (int)(e.getY()-initialClick.getX()));
        }
        else if(e.getY()>e.getX()){
            zoomBox=new Rectangle((int)initialClick.getX(), (int)initialClick.getY(), (int)(e.getX()-initialClick.getY()), (int)(e.getY()-initialClick.getY()));
        }
        else{
            zoomBox=new Rectangle((int)initialClick.getX(), (int)initialClick.getY(), (int)(e.getX()-initialClick.getX()), (int)(e.getY()-initialClick.getY()));
        }
        content=new JLabel(new ImageIcon(render(iterCounts, bufferedImage, zoomBox, false)));
        content.repaint();
    }

    protected static void handleMouseReleased(MouseEvent e) {
        recalculate(initialClick.getX(), initialClick.getY(), e.getX(), e.getY(), iterCounts);
        SwingUtilities.invokeLater(new Runnable(){
            @Override
            public void run() {
                zoomBox=null;
                content=new JLabel(new ImageIcon(render(iterCounts, bufferedImage, zoomBox, false)));
                content.repaint();
            }
        });
    }
}
公共类MandelbrotTask实现可运行{
专用双x1,y1,x2,y2;
私人int startCol、endCol、startRow、endRow、maxIters;
私有int[][]iterCounts;
公共MandelbrotTask(整数最大值、整数倍x1、整数倍y1、整数倍x2、整数倍y2、整数倍startCol、整数倍endCol、整数倍startRow、整数倍endRow、整数倍int[][]iterCounts){
这是1.x1=x1;
这是1.y1=y1;
这是0.x2=x2;
这1.y2=y2;
this.startCol=startCol;
this.endCol=endCol;
this.startRow=startRow;
this.endRow=endRow;
this.iterCounts=iterCounts;
这个。maxIters=maxIters;
}
@凌驾
公开募捐{
对于(int i=startRow;i虽然(z.getMagnitude()是其中一个,但每次重新迭代都会创建一个新的JLabel,而这个JLabel不会被添加到任何内容中

而是使用相同的JLabel,而是创建一个新的ImageIcon并设置查看的JLabel图标

ImageIcon icon = new ImageIcon(render(iterCounts, bufferedImage, zoomBox, false));
content.setIcon(icon);
您似乎也没有对重新计算返回的int数组做任何处理

您的handleMouseReleased方法不应该有:

iterCounts = recalculate(initialClick.getX(), initialClick.getY(), 
     e.getX(), e.getY(), iterCounts);
此外,线程仍然不好——您在Swing事件线程中调用线程连接,这几乎肯定会冻结您的GUI。使用SwingWorker,然后在收到工作人员的通知后,使用其数据。此外,您在GUI中过度使用静态变量。使您的GUI组件实例为fields,而不是静态字段

我还没有发现更多的逻辑错误,恐怕


程序的第二次迭代--和曼德尔布罗特计算:

导入java.awt.Color;
导入java.awt.Dimension;
导入java.awt.Graphics;
导入java.awt.Graphics2D;
导入java.awt.Point;
导入java.awt.Rectangle;
导入java.awt.Window;
导入java.awt.Dialog.ModalityType;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.awt.event.MouseAdapter;
导入java.awt.event.MouseEvent;
导入java.awt.image.buffereImage;
导入java.beans.PropertyChangeEvent;
导入java.beans.PropertyChangeListener;
导入java.util.concurrent.ExecutionException;
导入javax.swing.*;
@抑制警告(“串行”)
公共类Mandel2扩展了JPanel{
专用静态最终内部GUI_高度=600;
专用静态最终整数GUI_宽度=600;
专用静态最终整数最大值=50000;
私有缓冲区图像=新的缓冲区图像(GUI_宽度、GUI_高度、,
BuffereImage.TYPE_INT_ARGB);
私有矩形缩放;
私人双myX0=-2.5;
私人双MY0=-2.0;
私人双myX1=1.5;
私人双myY1=2.0;
私有JDialog对话框;
公共政策2(){
final MyMouse MyMouse=新的MyMouse();
int delayStartingCalc=2*1000;//2秒延迟
计时器计时器=新计时器(delayStartingCalc,new ActionListener(){
@凌驾
已执行的公共无效操作(操作事件e){
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
矩形myRect=新矩形(0,0,GUI\u宽度,GUI\u高度);
createMandel(myRect);
}
});
timer.setRepeats(假);
timer.start();
}
@凌驾
公共维度getPreferredSize(){
如果(isPreferredSizeSet()){
返回super.getPreferredSize();
}
返回新尺寸(GUI\U宽度、GUI\U高度);
}
@凌驾
受保护组件(图形g){
超级组件(g);
如果(图像!=null){
g、 drawImage(图像,0,0,this);
}
图形2d g2=(图形2d)g;
if(zoomRect==null){
返回;
}
g2.setXORMode(颜色:灰色);
g2.绘制(zoomRect);
}
专用双屏幕逻辑X(双屏幕X){
返回myX0+(screenX*(myX1-myX0))/GUI\u宽度;
}
私人双屏幕医学(双屏幕){
返回myY0+((GUI\u HEIGHT-screenY)*(myY1-myY0))/GUI\u HEIGHT;
}
私有void createMandel(矩形myRect){
双x0=屏幕逻辑x(myRect.x);
双y0=屏幕逻辑(myRect.y+myRect.height);
双x1=屏幕逻辑x(myRect.x+myRect.width);
双y1=sc