javafxgui与Swing的性能比较

javafxgui与Swing的性能比较,java,performance,swing,javafx,Java,Performance,Swing,Javafx,我写了两个简单的程序,都画了相同的Sierpinski三角形: 一个程序是使用swing实现的,另一个是使用javafx实现的。 有一个非常显著的性能差异,swing实现始终要快得多: (在这个测试用例中:Swing超过1秒,Javafx超过12秒)我的Javafx实现是意料之中的,还是出了什么问题 Swing实施 import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import jav

我写了两个简单的程序,都画了相同的Sierpinski三角形:
一个程序是使用swing实现的,另一个是使用javafx实现的。 有一个非常显著的性能差异,swing实现始终要快得多:


(在这个测试用例中: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;

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);
    }
}
导入java.awt.BorderLayout;
导入java.awt.Color;
导入java.awt.Dimension;
导入java.awt.Font;
导入java.awt.Graphics;
导入java.awt.Graphics2D;
导入java.awt.Point;
导入java.awt.Polygon;
导入java.awt.image.buffereImage;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
导入javax.swing.SwingUtilities;
公共类simplerpnsktrisw{
私人三角形三角板;
SimpleSPNSKTRISW(整数级){
JFrame=新JFrame(“Sierpinski三角形(swing)”);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
triPanel=新三角形();
frame.add(triPanel,BorderLayout.CENTER);
frame.pack();
frame.setresizeable(false);
frame.setVisible(true);
三平面图(层数);
}
类三角形扩展了JPanel{
专用静态最终内部面板宽度=600,面板高度=600;
专用静态最终内部TRI_宽度=500,TRI_高度=500;
专用静态最终内部侧间隙=(面板宽度-三角宽度)/2;
专用静态最终内部顶部间隙=(面板高度-三角高度)/2;
私有整数三角形;
私人长启动时间;
布尔运算;
私有int numberOfLevels=0;
三角形(){
setPreferredSize(新尺寸(面板宽度、面板高度));
startTime=System.currentTimeMillis();
可数三角形=0;
工作=真实;
draw();
}
虚线绘制(整数级){
numberOfLevels=numLevels;
工作=真实;
draw();
}
作废提款(){
startTime=System.currentTimeMillis();
可数三角形=0;
SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开募捐{
重新油漆();
}
});
}
@凌驾
公共组件(图形g){
超级组件(g);
g、 setFont(新字体(“Ariel”,Font.PLAIN,14));
如果(工作){
g、 setColor(getBackground());
g、 fillRect(0,0,面板宽度,面板高度);
g、 setColor(get前台());
g、 抽绳(“工作……”、15、15);
工作=假;
返回;
}
如果(数字级别0)){
试一试{
int num=Integer.parseInt(args[0]);
numberOfLevels=num;
}捕获(NumberFormatException ex){
例如printStackTrace();
返回;
}
}
应用程序启动(args);
}
@凌驾
公众假期开始(阶段){
stage.setOnCloseRequest((ae)->{
Platform.exit();
系统出口(0);
});
舞台。片名(“西格宾斯基三角形(fx)”;
BorderPane mainPane=新建BorderPane();
主窗格。设置填充(新插入(填充));
窗格triPanel=新三角形();
边框窗格。设置对齐(三面板,位置中心);
主窗格。设置中心(triPanel);
场景=新场景(主窗格);
舞台场景;
stage.centerOnScreen();
阶段。可设置大小(假);
stage.show();
}
类三角形扩展锚链{
专用静态最终内部面板宽度=600,面板高度=600;
专用静态最终内部TRI_宽度=500,TRI_高度=500;
专用静态最终内部侧间隙=(面板宽度-三角宽度)/2;
专用静态最终内部顶部间隙=(面板高度-三角高度)/2;
私有整数三角形;
私人长启动时间;
私有点2D顶部、左侧、右侧;
私人帆布;
私人画布背景画布;
私有图形上下文gc;
三角形(){
setPrefSize(面板宽度、面板高度);
canvas=getCanvas();
backgroundCanvas=getCanvas();
gc=backgroundCanvas.getGraphicsContext2D();
getChildren().add(画布);
绘制(层数);
}
无效绘制(整数级){
Platform.runLater(新的Runnable(){
@凌驾
公开募捐{
canvas.getGraphicsContext2D().fillText(“工作…”),5,15;
设置起点();
startTime=System.currentTimeMillis();
可数三角形=0;
RunTask task=新的RunTask(数级、上、左、右);
线程线程=新线程(任务);
setDaemon(true);
thread.start();
}
});
}
私有void drawTriangle(int Level、Point2D top、Point2D left、Point2D right){
如果(级别<0){//添加停止条件
返回;
}
strokePolygon(//使用strokeLine实现没有多大区别
新双[]{
top.getX(),left.getX(),right.getX()
},
新双[]{
top.getY(),left.getY(),right.getY()
},
3);
可数三角形++;
//获取三角形中每条边的中点
点2D p12=中点(顶部,左侧);
点2D p23=中点(左、右);
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");
    }
}
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);
    }

}