JavaFx Gui与Swing的性能 [英] Performance of JavaFx Gui vs Swing

查看:368
本文介绍了JavaFx Gui与Swing的性能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了两个简单的程序,两个都绘制​​了相同的Sierpinski三角形:


一个程序是使用swing实现的,一个是使用javafx实现的。
有一个非常显着的性能差异,swing实现持续快得多:





(在这个测试案例中:超过1秒摆动.Javafx超过12秒)
我的javafx实现是否可以预料到或者出现了什么问题?



Swing实施

  import java .awt.BorderLayout; 
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

公共类SimpleSrpnskTriSw {

private Triangles triPanel;

SimpleSrpnskTriSw(int numberOfLevels){

JFrame frame = new JFrame(Sierpinski Triangles(swing));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

triPanel = new Triangles();
frame.add(triPanel,BorderLayout.CENTER);
frame.pack();

frame.setResizable(false);
frame.setVisible(true);

triPanel.draw(numberOfLevels);
}

类三角形扩展JPanel {

private static final int PANEL_WIDTH = 600,PANEL_HEIGHT = 600;
private static final int TRI_WIDTH = 500,TRI_HEIGHT = 500;
private static final int SIDE_GAP =(PANEL_WIDTH - TRI_WIDTH)/ 2;
private static final int TOP_GAP =(PANEL_HEIGHT - TRI_HEIGHT)/ 2;

private int countTriangles;
private long startTime;
布尔工作;
private int numberOfLevels = 0;

Triangles(){

setPreferredSize(new Dimension(PANEL_WIDTH,PANEL_HEIGHT));
startTime = System.currentTimeMillis();
countTriangles = 0;
working = true;
draw();
}

void draw(int numLevels){

numberOfLevels = numLevels;
working = true;
draw();
}

void draw(){

startTime = System.currentTimeMillis();
countTriangles = 0;

SwingUtilities.invokeLater(new Runnable(){
@Override
public void run(){

repaint();
}
});
}

@Override
public void paintComponent(Graphics g){

super.paintComponent(g);
g.setFont(new Font(Ariel,Font.PLAIN,14));

if(working){

g.setColor(getBackground());
g.fillRect(0,0,PANEL_WIDTH,PANEL_HEIGHT);
g.setColor(getForeground());

g.drawString(Working .........,15,15);
working = false;
返回;
}

if(numberOfLevels< = 0){
return;
}
点顶部=新点(PANEL_WIDTH / 2,TOP_GAP);
点左=新点(SIDE_GAP,TOP_GAP + TRI_HEIGHT);
Point right = new Point(SIDE_GAP + TRI_WIDTH,TOP_GAP + TRI_HEIGHT);

BufferedImage bi = getBufferedImage(top,left,right);
Graphics2D g2d =(Graphics2D)g;
g2d.drawImage(bi,0,0,this);

g.drawString(三角形数:+ countTriangles,15,15);
g.drawString(Time:+(System.currentTimeMillis() - startTime)+mili seconds,15,35);
g.drawString(Levels:+ numberOfLevels,15,50);
}

private BufferedImage getBufferedImage(Point top,Point left,Point right){

BufferedImage bi = new BufferedImage(PANEL_WIDTH,PANEL_HEIGHT,
BufferedImage .TYPE_INT_ARGB);
drawTriangle(bi,numberOfLevels,top,left,right);
返回bi;
}

private void drawTriangle(BufferedImage bi,int levels,Point top,Point left,Point right){

if(levels< 0){
返回;
}

countTriangles ++;
Graphics g = bi.getGraphics();
g.setColor(Color.RED);

Polygon tri = new Polygon();
tri.addPoint(top.x,top.y); //使用top,left right而不是固定点
tri.addPoint(left.x,left.y);
tri.addPoint(right.x,right.y);
g.drawPolygon(tri);

//获取三角形中每条边的中点
点p12 =中点(上,左);
点p23 =中点(左,右);
点p31 =中点(右,上);

//递归3个三角形区域
drawTriangle(bi,levels - 1,top,p12,p31);
drawTriangle(bi,levels - 1,p12,left,p23);
drawTriangle(bi,levels - 1,p31,p23,right);
}

私人点中点(点p1,点p2){

返回新点((p1.x + p2.x)/ 2,(p1 .y + p2.y)/ 2);
}
}

public static void main(String [] args){

new SimpleSrpnskTriSw(13);
}
}

JavaFx实施

  import javafx.application.Application; 
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

公共类SimpleSrpnskTriFx扩展Application {

private final int PADDING = 5;
private static int numberOfLevels;

public static void launch(String ... args){

numberOfLevels = 8;

if((args!= null)&&(args.length> 0)){

try {
int num = Integer.parseInt (参数[0]);
numberOfLevels = num;
} catch(NumberFormatException ex){
ex.printStackTrace();
返回;
}
}

Application.launch(args);
}

@Override
public void start(阶段阶段){

stage.setOnCloseRequest((ae) - > {
Platform.exit();
System.exit(0);
});

stage.setTitle(Sierpinski Triangles(fx));

BorderPane mainPane = new BorderPane();
mainPane.setPadding(new Insets(PADDING));

Pane triPanel = new Triangles();

BorderPane.setAlignment(triPanel,Pos.CENTER);
mainPane.setCenter(triPanel);

场景场景=新场景(mainPane);

stage.setScene(场景);
stage.centerOnScreen();

stage.setResizable(false);
stage.show();
}

类三角形扩展AnchorPane {

private static final int PANEL_WIDTH = 600,PANEL_HEIGHT = 600;
private static final int TRI_WIDTH = 500,TRI_HEIGHT = 500;
private static final int SIDE_GAP =(PANEL_WIDTH - TRI_WIDTH)/ 2;
private static final int TOP_GAP =(PANEL_HEIGHT - TRI_HEIGHT)/ 2;
private int countTriangles;
private long startTime;
私人Point2D上,左,右;

私人帆布帆布;
private Canvas backgroundCanvas;
private GraphicsContext gc;

Triangles(){

setPrefSize(PANEL_WIDTH,PANEL_HEIGHT);

canvas = getCanvas();
backgroundCanvas = getCanvas();
gc = backgroundCanvas.getGraphicsContext2D();
getChildren()。add(canvas);
draw(numberOfLevels);
}

void draw(int numberLevels){

Platform.runLater(new Runnable(){

@Override
public void run(){

canvas.getGraphicsContext2D()。fillText(Working ....,5,15);
setStartPoints();

startTime = System.currentTimeMillis();
countTriangles = 0;

RunTask task = new RunTask(numberLevels,top,left,right);
Thread thread = new Thread (任务);
thread.setDaemon(true);
thread.start();
}
});
}

private void drawTriangle(int levels,Point2D top,Point2D left,Point2D right){

if(levels< 0){// add stop标准
返回;
}

gc.strokePolygon(//用strokeLine实现没有太大区别
new double [] {
top.getX(),left.getX( ),right.getX()
},
new double [] {
top.getY(),left.getY(),right.getY()
},
3);

countTriangles ++;

//获取三角形中每条边的中点
Point2D p12 =中点(上,左);
Point2D p23 =中点(左,右);
Point2D p31 =中点(右,上);

//递归到3个三角形区域
drawTriangle(level - 1,top,p12,p31);
drawTriangle(level - 1,p12,left,p23);
drawTriangle(级别 - 1,p31,p23,右);
}

private void setStartPoints(){

top = new Point2D(getPrefWidth()/ 2,TOP_GAP);
left = new Point2D(SIDE_GAP,TOP_GAP + TRI_HEIGHT);
right = new Point2D(SIDE_GAP + TRI_WIDTH,TOP_GAP + TRI_WIDTH);
}

私人Point2D中点(Point2D p1,Point2D p2){

返回新Point2D((p1.getX()+ p2.getX())/
2,(p1.getY()+ p2.getY())/ 2);
}

private void updateGraphics(布尔成功){

if(成功){

copyCanvas();

GraphicsContext gc = canvas.getGraphicsContext2D();
gc.fillText(三角形数:+ countTriangles,5,15);
gc.fillText(Time:+(System.currentTimeMillis() - startTime)+mili seconds,5,35);
gc.fillText(Levels:+ numberOfLevels,5,55);
}

}

private Canvas getCanvas(){

Canvas canvas = new Canvas();
canvas.widthProperty()。bind(widthProperty());
canvas.heightProperty()。bind(heightProperty());
canvas.getGraphicsContext2D()。setStroke(Color.RED);
canvas.getGraphicsContext2D()。setLineWidth(0.3f);

返回画布;
}

private void copyCanvas(){

WritableImage image = backgroundCanvas.snapshot(null,null);
canvas.getGraphicsContext2D()。drawImage(image,0,0);
}

/ **
* /
类RunTask扩展Task< Void> {

私有int级别;
私人Point2D顶部,左边;
私有Point2D吧;

RunTask(int level,Point2D top,Point2D left,Point2D right){

this.levels = levels;
this.top = top;
this.left = left;
this.right = right;

startTime = System.currentTimeMillis();
countTriangles = 0;
}

@Override public Void call(){

drawTriangle(levels,top,left,right);
返回null;
}

@Override
protected void succeeded(){

updateGraphics(true);
super.succeeded();
}

@Override
protected void failed(){

updateGraphics(false);
}
}
}

public static void main(String [] args){
launch(13);
}
}


解决方案

Swing示例将图像展平到600 2 = 360,000像素。相比之下,JavaFX示例在最终渲染时会渲染近240万个重叠多边形。请注意,您的JavaFX示例测量两者组成分形的时间和

  import java.awt.Color; 
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.image.BufferedImage;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

/ **
* @see https://stackoverflow.com/q/44136040/230513
* /
公共类BufferedImageTest扩展应用程序{

private static final int PANEL_WIDTH = 600,PANEL_HEIGHT = 600;
private static final int TRI_WIDTH = 500,TRI_HEIGHT = 500;
private static final int SIDE_GAP =(PANEL_WIDTH - TRI_WIDTH)/ 2;
private static final int TOP_GAP =(PANEL_HEIGHT - TRI_HEIGHT)/ 2;
private final int numberOfLevels = 13;
private int countTriangles;

@Override
public void start(舞台阶段){
stage.setTitle(BufferedImageTest);
StackPane root = new StackPane();
场景场景=新场景(根);
root.getChildren()。add(new ImageView(createImage()));
stage.setScene(场景);
stage.show();
}

private Image createImage(){
BufferedImage bi = new BufferedImage(
PANEL_WIDTH,PANEL_HEIGHT,BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.setPaint(Color.white);
g.fillRect(0,0,PANEL_WIDTH,PANEL_HEIGHT);
指向顶部=新点(PANEL_WIDTH / 2,TOP_GAP);
点左=新点(SIDE_GAP,TOP_GAP + TRI_HEIGHT);
Point right = new Point(SIDE_GAP + TRI_WIDTH,TOP_GAP + TRI_HEIGHT);
g.setColor(Color.red);
long startTime = System.currentTimeMillis();
drawTriangle(g,numberOfLevels,top,left,right);
g.setPaint(Color.black);
g.drawString(三角形数:+ countTriangles,15,15);
g.drawString(Time:+(System.currentTimeMillis() - startTime)+ms,15,35);
g.drawString(Levels:+ numberOfLevels,15,50);
WritableImage image = SwingFXUtils.toFXImage(bi,null);
g.dispose();
返回图片;
}

private void drawTriangle(Graphics2D g,int levels,Point top,Point left,Point right){
if(levels< 0){
return ;
}
countTriangles ++;
Polygon tri = new Polygon();
tri.addPoint(top.x,top.y);
tri.addPoint(left.x,left.y);
tri.addPoint(right.x,right.y);
g.drawPolygon(tri);

//获取三角形中每条边的中点
点p12 =中点(上,左);
点p23 =中点(左,右);
点p31 =中点(右,上);

//递归3个三角形区域
drawTriangle(g,levels - 1,top,p12,p31);
drawTriangle(g,levels - 1,p12,left,p23);
drawTriangle(g,levels - 1,p31,p23,right);
}

私有点中点(点p1,点p2){
返回新点((p1.x + p2.x)/ 2,(p1.y + p2) .y)/ 2);
}

public static void main(String [] args){
launch(args);
}

}


I wrote two simple programs, both draw the same Sierpinski Triangle:
One program was implemented using swing, and one using javafx. There is a very significant performance difference, swing implementation being consistently much faster:


(In this test case : Swing over 1 sec. Javafx over 12 seconds)
Is it to be expected or is there something very wrong with my javafx implementation ?

Swing implementation

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class SimpleSrpnskTriSw {

    private Triangles triPanel;

    SimpleSrpnskTriSw(int numberOfLevels){

        JFrame frame = new JFrame("Sierpinski Triangles (swing)");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        triPanel = new Triangles();
        frame.add(triPanel, BorderLayout.CENTER);
        frame.pack();

        frame.setResizable(false);
        frame.setVisible(true);

        triPanel.draw(numberOfLevels);
    }

    class Triangles extends JPanel{

        private static final int PANEL_WIDTH =600, PANEL_HEIGHT = 600;
        private static final int TRI_WIDTH= 500, TRI_HEIGHT= 500;
        private static final int SIDE_GAP = (PANEL_WIDTH - TRI_WIDTH)/2;
        private static final int TOP_GAP = (PANEL_HEIGHT - TRI_HEIGHT)/2;

        private int countTriangles;
        private long startTime;
        boolean working;
        private int numberOfLevels = 0;

        Triangles() {

            setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
            startTime = System.currentTimeMillis();
            countTriangles = 0;
            working = true;
            draw();
        }

        void draw(int numLevels) {

            numberOfLevels = numLevels;
            working = true;
            draw();
        }

        void draw() {

            startTime = System.currentTimeMillis();
            countTriangles = 0;

            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {

                    repaint();
                }
            });
        }

        @Override
        public void paintComponent(Graphics g) {

            super.paintComponent(g);
            g.setFont(new Font("Ariel", Font.PLAIN, 14));

            if(working) {

                g.setColor(getBackground());
                g.fillRect(0,0,PANEL_WIDTH,PANEL_HEIGHT);
                g.setColor(getForeground());

                g.drawString("Working.........", 15, 15);
                working = false;
                return;
            }

            if(numberOfLevels <= 0 ) {
                return;
            }
            Point top = new Point(PANEL_WIDTH/2, TOP_GAP);
            Point left = new Point(SIDE_GAP, TOP_GAP+ TRI_HEIGHT);
            Point right = new Point(SIDE_GAP + TRI_WIDTH, TOP_GAP+ TRI_HEIGHT);

            BufferedImage bi = getBufferedImage(top, left, right);
            Graphics2D g2d = (Graphics2D) g;
            g2d.drawImage(bi,0,0, this);

            g.drawString("Number of triangles: "+ countTriangles, 15, 15);
            g.drawString("Time : "+ (System.currentTimeMillis()- startTime)+ " mili seconds", 15, 35);
            g.drawString("Levels: "+ numberOfLevels, 15, 50);
        }

        private BufferedImage getBufferedImage(Point top, Point left, Point right) {

            BufferedImage bi = new BufferedImage(PANEL_WIDTH,PANEL_HEIGHT,
                                                            BufferedImage.TYPE_INT_ARGB);
            drawTriangle(bi, numberOfLevels, top, left, right);
            return bi;
        }

        private void drawTriangle(BufferedImage bi, int levels, Point top, Point left, Point right) {

            if(levels < 0) {
                return ;
            }

            countTriangles++;
            Graphics g = bi.getGraphics();
            g.setColor(Color.RED);

            Polygon tri = new Polygon();
            tri.addPoint(top.x, top.y);  //use top,left right rather than fixed points
            tri.addPoint(left.x, left.y);
            tri.addPoint(right.x, right.y);
            g.drawPolygon(tri);

            // Get the midpoint on each edge in the triangle
            Point p12 = midpoint(top, left);
            Point p23 = midpoint(left, right);
            Point p31 = midpoint(right, top);

            // recurse on 3 triangular areas
            drawTriangle(bi, levels - 1, top, p12, p31);
            drawTriangle(bi, levels - 1, p12, left, p23);
            drawTriangle(bi, levels - 1, p31, p23, right);
        }

        private Point midpoint(Point p1, Point p2) {

            return new Point((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);
        }
    }

    public static void main(String[] args) {

        new SimpleSrpnskTriSw(13);
    }
}

JavaFx implementation

import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class SimpleSrpnskTriFx extends Application {

    private final int PADDING = 5;
    private static int numberOfLevels;

    public static void launch(String... args){

        numberOfLevels = 8;

        if((args != null) && (args.length > 0)) {

            try {
                int num = Integer.parseInt(args[0]);
                numberOfLevels =  num ;
            } catch (NumberFormatException ex) {
                ex.printStackTrace();
                return;
            }
        }

        Application.launch(args);
    }

    @Override
    public void start(Stage stage) {

        stage.setOnCloseRequest((ae) -> {
            Platform.exit();
            System.exit(0);
        });

        stage.setTitle("Sierpinski Triangles (fx)");

        BorderPane mainPane = new BorderPane();
        mainPane.setPadding(new Insets(PADDING));

        Pane triPanel = new Triangles();

        BorderPane.setAlignment(triPanel, Pos.CENTER);
        mainPane.setCenter(triPanel);

        Scene scene = new Scene(mainPane);

        stage.setScene(scene);
        stage.centerOnScreen();

        stage.setResizable(false);
        stage.show();
    }

    class Triangles extends AnchorPane{

        private static final int PANEL_WIDTH =600, PANEL_HEIGHT = 600;
        private static final int TRI_WIDTH= 500, TRI_HEIGHT= 500;
        private static final int SIDE_GAP = (PANEL_WIDTH - TRI_WIDTH)/2;
        private static final int TOP_GAP = (PANEL_HEIGHT - TRI_HEIGHT)/2;
        private int countTriangles;
        private long startTime;
        private Point2D top, left, right;

        private Canvas canvas;
        private Canvas backgroundCanvas;
        private GraphicsContext gc;

        Triangles(){

            setPrefSize(PANEL_WIDTH, PANEL_HEIGHT);

            canvas = getCanvas();
            backgroundCanvas = getCanvas();
            gc = backgroundCanvas.getGraphicsContext2D();
            getChildren().add(canvas);
            draw(numberOfLevels);
        }

        void draw(int numberLevels) {

            Platform.runLater(new Runnable() {

                @Override
                public void run() {

                    canvas.getGraphicsContext2D().fillText("Working....",5,15);
                    setStartPoints();

                    startTime = System.currentTimeMillis();
                    countTriangles = 0;

                    RunTask task = new RunTask(numberLevels, top, left, right);
                    Thread thread = new Thread(task);
                    thread.setDaemon(true);
                    thread.start();
                }
            });
        }

        private void drawTriangle( int levels, Point2D top, Point2D left, Point2D right) {

            if(levels < 0) {//add stop criteria
                return ;
            }

            gc.strokePolygon( //implementing with strokeLine did not make much difference
                    new double[]{
                            top.getX(),left.getX(),right.getX()
                    },
                    new double[]{
                            top.getY(),left.getY(), right.getY()
                    },
                    3);

            countTriangles++;

            //Get the midpoint on each edge in the triangle
            Point2D p12 = midpoint(top, left);
            Point2D p23 = midpoint(left, right);
            Point2D p31 = midpoint(right, top);

            // recurse on 3 triangular areas
            drawTriangle(levels - 1, top, p12, p31);
            drawTriangle(levels - 1, p12, left, p23);
            drawTriangle(levels - 1, p31, p23, right);
        }

        private void setStartPoints() {

            top = new Point2D(getPrefWidth()/2, TOP_GAP);
            left = new Point2D(SIDE_GAP, TOP_GAP + TRI_HEIGHT);
            right = new Point2D(SIDE_GAP + TRI_WIDTH, TOP_GAP + TRI_WIDTH);
        }

        private Point2D midpoint(Point2D p1, Point2D p2) {

            return new Point2D((p1.getX() + p2.getX()) /
                    2, (p1.getY() + p2.getY()) / 2);
        }

        private void updateGraphics(boolean success){

            if(success) {

                copyCanvas();

                GraphicsContext gc = canvas.getGraphicsContext2D();
                gc.fillText("Number of triangles: "+ countTriangles,5,15);
                gc.fillText("Time : "+ (System.currentTimeMillis()- startTime )+ " mili seconds", 5,35);
                gc.fillText("Levels: "+ numberOfLevels,5,55);
            }

        }

        private Canvas getCanvas() {

            Canvas canvas = new Canvas();
            canvas.widthProperty().bind(widthProperty());
            canvas.heightProperty().bind(heightProperty());
            canvas.getGraphicsContext2D().setStroke(Color.RED);
            canvas.getGraphicsContext2D().setLineWidth(0.3f);

            return canvas;
        }

        private void copyCanvas() {

            WritableImage image = backgroundCanvas.snapshot(null, null);
            canvas.getGraphicsContext2D().drawImage(image, 0, 0);
        }

        /**
         */
        class RunTask extends Task<Void>{

            private int levels;
            private Point2D top, left;
            private Point2D right;

            RunTask(int levels, Point2D top, Point2D left, Point2D right){

                this.levels = levels;
                this.top = top;
                this.left = left;
                this.right = right;

                startTime = System.currentTimeMillis();
                countTriangles = 0;
            }

            @Override public Void call() {

                drawTriangle(levels,top, left, right);
                return null;
            }

            @Override
            protected void succeeded() {

                updateGraphics(true);
                super.succeeded();
            }

            @Override
            protected void failed() {

                updateGraphics(false);
            }
        }
    }

    public static void main(String[] args) {
        launch("13");
    }
}

解决方案

The Swing example flattens the image to 6002 = 360,000 pixels. In contrast, the JavaFX example strokes almost 2.4 million overlapping polygons when finally rendered. Note that your JavaFX example measures both the time to compose the fractal and the time to render it in the scene graph.

If you want to preserve the strokes comprising the fractal, compose the result in a Canvas, as shown here.

If a flat Image is sufficient, compose the result in a BufferedImage, convert it to a JavaFX Image, and display it in an ImageView, as shown below. The JavaFX result is over a second faster than the Swing example on my hardware.

Because SwingFXUtils.toFXImage makes a copy, a background Task<Image> could continue to update a single BufferedImage while publishing interim Image results via updateValue().

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.image.BufferedImage;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

/**
 * @see https://stackoverflow.com/q/44136040/230513
 */
public class BufferedImageTest extends Application {

    private static final int PANEL_WIDTH = 600, PANEL_HEIGHT = 600;
    private static final int TRI_WIDTH = 500, TRI_HEIGHT = 500;
    private static final int SIDE_GAP = (PANEL_WIDTH - TRI_WIDTH) / 2;
    private static final int TOP_GAP = (PANEL_HEIGHT - TRI_HEIGHT) / 2;
    private final int numberOfLevels = 13;
    private int countTriangles;

    @Override
    public void start(Stage stage) {
        stage.setTitle("BufferedImageTest");
        StackPane root = new StackPane();
        Scene scene = new Scene(root);
        root.getChildren().add(new ImageView(createImage()));
        stage.setScene(scene);
        stage.show();
    }

    private Image createImage() {
        BufferedImage bi = new BufferedImage(
            PANEL_WIDTH, PANEL_HEIGHT, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = bi.createGraphics();
        g.setPaint(Color.white);
        g.fillRect(0, 0, PANEL_WIDTH, PANEL_HEIGHT);
        Point top = new Point(PANEL_WIDTH / 2, TOP_GAP);
        Point left = new Point(SIDE_GAP, TOP_GAP + TRI_HEIGHT);
        Point right = new Point(SIDE_GAP + TRI_WIDTH, TOP_GAP + TRI_HEIGHT);
        g.setColor(Color.red);
        long startTime = System.currentTimeMillis();
        drawTriangle(g, numberOfLevels, top, left, right);
        g.setPaint(Color.black);
        g.drawString("Number of triangles: " + countTriangles, 15, 15);
        g.drawString("Time : " + (System.currentTimeMillis() - startTime) + " ms", 15, 35);
        g.drawString("Levels: " + numberOfLevels, 15, 50);
        WritableImage image = SwingFXUtils.toFXImage(bi, null);
        g.dispose();
        return image;
    }

    private void drawTriangle(Graphics2D g, int levels, Point top, Point left, Point right) {
        if (levels < 0) {
            return;
        }
        countTriangles++;
        Polygon tri = new Polygon();
        tri.addPoint(top.x, top.y);
        tri.addPoint(left.x, left.y);
        tri.addPoint(right.x, right.y);
        g.drawPolygon(tri);

        // Get the midpoint on each edge in the triangle
        Point p12 = midpoint(top, left);
        Point p23 = midpoint(left, right);
        Point p31 = midpoint(right, top);

        // recurse on 3 triangular areas
        drawTriangle(g, levels - 1, top, p12, p31);
        drawTriangle(g, levels - 1, p12, left, p23);
        drawTriangle(g, levels - 1, p31, p23, right);
    }

    private Point midpoint(Point p1, Point p2) {
        return new Point((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);
    }

    public static void main(String[] args) {
        launch(args);
    }

}

这篇关于JavaFx Gui与Swing的性能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆