Java 更改BuffereImage的内容,然后更新JFrame以反映它
我正在尝试制作一个带有GUI的Mandelbrot集渲染器,您可以在其中单击并拖动以放大到特定区域。运行时,它将进行初始计算并进行精细渲染,但当您尝试单击并拖动以放大时,控制台会说它正在进行计算,但JFrame的内容不会更新 但是,我甚至不确定它是否正在重新计算,因为初始计算大约需要8秒,但当您单击/拖动缩放时,大约需要6毫秒 我已经在下面发布了我的代码 复数类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
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