SeanLetendre SeanLetendre - 1 month ago 12
Java Question

Java FX Canvas doesn't show until complete

I want to create a java FX application that draws lines on a Canvas one step at a time, with a noticable time between line segments. In the below application I have what I imagined would draw a diagonal line, stall a second and then draw the next diagonal line. Instead, the FX window pops up blank, waits 2 seconds, and then shows the two diagonal lines at the same time. How do I achieve the effect I am looking for? Is

javafx.scene.canvas.Canvas
not the right object to be using?

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;

import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;

public class FrameCanvas extends Application{
public static void main(String[] args){
launch(args);
}
@Override
public void start(Stage primaryStage)throws Exception{
////////////////////Basic FX stuff
Canvas theCanvas = new Canvas(900,900);
StackPane theLayout = new StackPane();
theLayout.getChildren().add(theCanvas);
Scene theScene = new Scene(theLayout,900,900);
primaryStage.setScene(theScene);
primaryStage.show();
///////////////////////
/////Drawing an X
///////////////////////
GraphicsContext gc = theCanvas.getGraphicsContext2D();
Thread.sleep(1000);
gc.strokeLine(0,0,200,200);
Thread.sleep(1000);
gc.strokeLine(200,0,0,200);
/////////////////////////////
}
}

Answer

Don't block (e.g. Thread.sleep(...)) the FX Application Thread. That thread is responsible for rendering the scene, so you will prevent any updates from being rendered.

Instead, use an animation for functionality like this (after all, an animation is really what you're creating here):

public void start(Stage primaryStage)throws Exception{
    ////////////////////Basic FX stuff
    Canvas theCanvas = new Canvas(900,900);
    StackPane theLayout = new StackPane();
    theLayout.getChildren().add(theCanvas);
    Scene theScene = new Scene(theLayout,900,900);
    primaryStage.setScene(theScene);
    primaryStage.show();
    ///////////////////////
    /////Drawing an X
    ///////////////////////
    GraphicsContext gc = theCanvas.getGraphicsContext2D();

    Timeline timeline = new Timeline(
        new KeyFrame(Duration.seconds(1), e -> gc.strokeLine(0,0,200,200)),
        new KeyFrame(Duration.seconds(2), e -> gc.strokeLine(200,0,0,200))
    );
    timeline.play();
    /////////////////////////////
}