performance - জাভাএফএক্স ক্যানভাস অ্যাপ্লিকেশন সময়



swing javafx (1)

আপনার Task একটি Canvas আপডেট করার জন্য পটভূমিতে drawTriangle() আহ্বান করে। সম্পর্কিত GraphicsContext জন্য "একবার কোনও Canvas নোড কোনও দৃশ্যের সাথে সংযুক্ত হয়ে গেলে, এটি অবশ্যই জাভাএফএক্স অ্যাপ্লিকেশন থ্রেডে পরিবর্তন করতে হবে।" আপনার গভীরভাবে পুনরাবৃত্ত কলটি জাভাএফএক্স অ্যাপ্লিকেশন থ্রেডকে ব্লক করে, সময়োপত স্ক্রিন আপডেটকে প্রতিরোধ করে। বিপরীতে, আপনার প্ল্যাটফর্মের System.out.println() এর বাস্তবায়ন এটি একটি সময় মতো রিপোর্ট করার allow দিতে পারে। টাইমিং বৈষম্য এমনকি কোনও Task ছাড়াই দেখা যায়।

Canvas জন্য সুখের বিষয়, "এটি যদি কোনও দৃশ্যের সাথে সংযুক্ত না হয়, তবে এটি কোনও থ্রেড দ্বারা সংশোধন করা যায়, যতক্ষণ না এটি একবারে কেবল একটি থ্রেড থেকে ব্যবহৃত হয়।" একটি পদ্ধতির প্রস্তাব দেওয়া যেতে পারে Task । একটি কল্পিত Task<Image> তৈরি করুন যা পটভূমিতে একটি বিচ্ছিন্ন Canvas আপডেট করে। পর্যায়ক্রমে, সম্ভবত পুনরাবৃত্তির প্রতিটি স্তরে Canvas copy করুন এবং updateValue() মাধ্যমে একটি স্ন্যাপশট প্রকাশ করুন। ঘেরযুক্ত Pane কার্যের value সম্পত্তিটি শুনতে এবং জাভাএফএক্স অ্যাপ্লিকেশন drawImage() ব্লক না করে drawImage() মাধ্যমে একটি সংযুক্ত Canvas আপডেট করতে পারে।

দুঃখের সাথে, স্ন্যাপশট "জাভাএফএক্স অ্যাপ্লিকেশন থ্রেড ব্যতীত অন্য কোনও থ্রেডে এই পদ্ধতিটি IllegalStateException হলে" IllegalStateException করে।

নীচে প্রদর্শিত CanvasTask , Task<Canvas> প্রসারিত করে এবং একটি লুপের প্রতিটি পুনরাবৃত্তিতে একটি নতুন Canvas প্রকাশ করে। CanvasTaskTest Canvas CanvasTaskTest value সম্পত্তির কথা শুনে এবং প্রতিবার নতুন আসার সময় আগের Canvas প্রতিস্থাপন করে। নীচের উদাহরণটি ক্রমবর্ধমান গভীরতার ক্র্যাক্টাল গাছগুলির একটি সিরিজ এবং প্রতিটি রচনা করার জন্য প্রয়োজনীয় সময় প্রদর্শন করে। নোট করুন যে GraphicsContext , "প্রতিটি কল বাফারে প্রয়োজনীয় পরামিতিগুলি ঠেলে দেয় যেখানে পরে সেগুলি Canvas শেষে রেন্ডারিং থ্রেড দ্বারা Canvas নোডের চিত্রটিতে রেন্ডার করা হবে।" এটি জাভাএফএক্সকে প্ল্যাটফর্মের রেন্ডারিং পাইপলাইনটি উত্সাহ দেওয়ার অনুমতি দেয় তবে এটি প্রচুর স্ট্রোকের জন্য অতিরিক্ত ওভারহেড চাপিয়ে দিতে পারে। অনুশীলনে, কয়েক হাজার স্ট্রোক অযৌক্তিকভাবে উপস্থাপনকে ধীর করে দেয়, কয়েক মিলিয়ন ওভারল্যাপিং স্ট্রোক অতিরিক্ত অতিরিক্ত হতে পারে।

import javafx.application.Application;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

/**
 * @see https://stackoverflow.com/a/44056730/230513
 */
public class CanvasTaskTest extends Application {

    private static final int W = 800;
    private static final int H = 600;

    @Override
    public void start(Stage stage) {
        stage.setTitle("CanvasTaskTest");
        StackPane root = new StackPane();
        Canvas canvas = new Canvas(W, H);
        root.getChildren().add(canvas);
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
        CanvasTask task = new CanvasTask();
        task.valueProperty().addListener((ObservableValue<? extends Canvas> observable, Canvas oldValue, Canvas newValue) -> {
            root.getChildren().remove(oldValue);
            root.getChildren().add(newValue);
        });
        Thread thread = new Thread(task);
        thread.setDaemon(true);
        thread.start();
    }

    private static class CanvasTask extends Task<Canvas> {

        private int strokeCount;

        @Override
        protected Canvas call() throws Exception {
            Canvas canvas = null;
            for (int i = 1; i < 15; i++) {
                canvas = new Canvas(W, H);
                GraphicsContext gc = canvas.getGraphicsContext2D();
                strokeCount = 0;
                long start = System.nanoTime();
                drawTree(gc, W / 2, H - 50, -Math.PI / 2, i);
                double dt = (System.nanoTime() - start) / 1_000d;
                gc.fillText("Depth: " + i
                    + "; Strokes: " + strokeCount
                    + "; Time : " + String.format("%1$07.1f", dt) + " µs", 8, H - 8);
                Thread.sleep(200); // simulate rendering latency
                updateValue(canvas);
            }
            return canvas;
        }

        private void drawTree(GraphicsContext gc, int x1, int y1, double angle, int depth) {
            if (depth == 0) {
                return;
            }
            int x2 = x1 + (int) (Math.cos(angle) * depth * 5);
            int y2 = y1 + (int) (Math.sin(angle) * depth * 5);
            gc.strokeLine(x1, y1, x2, y2);
            strokeCount++;
            drawTree(gc, x2, y2, angle - Math.PI / 8, depth - 1);
            drawTree(gc, x2, y2, angle + Math.PI / 8, depth - 1);
        }
    }

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

}

আমি জাভাএফএক্স অনুশীলনের আদেশ দিয়েছি, আমি একটি সাধারণ অ্যাপ্লিকেশন তৈরি করেছি যা সিয়েরপিনস্কি ট্রায়াঙ্গলস আঁকবে

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.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class SierpinskiTriangles 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)) {

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

            numberOfLevels = (num > 0) ? num : numberOfLevels;
        }

        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 GraphicsContext gc;

        Triangles(){

            setPrefSize(PANEL_WIDTH, PANEL_HEIGHT);

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

        void draw(int numberLevels) {

            Platform.runLater(new Runnable() {

                @Override
                public void run() {

                    clearCanvas();
                    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) {

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

            System.out.println("Completed after: "+
                    (System.currentTimeMillis()- startTime)+ " mili seconds"
                    +"  Triangles: " + countTriangles  +"  Failed: "+ !success );
        }

        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 clearCanvas() {

            gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
        }

        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");
    }
}


আউটপুটটি প্রত্যাশার মতো:

আমার যে সমস্যাগুলি রয়েছে:

ক। updateGraphics() -এর টাইম প্রিন্টআউটটি updateGraphics() আমার মেশিনে 8 সেকেন্ড updateGraphics() অনেক আগে দেখায় ত্রিভুজগুলির অঙ্কন শেষ হয়েছে, সুতরাং এটি সম্পূর্ণ প্রক্রিয়াটি পরিমাপ করে না। আমি কীভাবে এটি উন্নতি করব?

খ। আমার মেশিনে প্যানেল সম্পূর্ণরূপে আঁকা না হওয়া পর্যন্ত এটি 30-30 মিনিট সময় নেয়। একটি অনুরূপ সুইং অ্যাপ্লিকেশন 4 সেকেন্ড সময় নেয়। এটি হতে পারে যে আমার জাভাফ্যাক্স বাস্তবায়নে মূলত কিছু ভুল আছে।





graphics