JavaFX: Hide Pane for a very short time


Question

I'm looking for a way to hide a Pane for a short time (around 100ms) and then immediately show it again.

Right now I'm using a StackPane with two AnchorPanes on top, and on key press I remove the top pane. However, that doesn't seem to happen immediately and it takes way too long.

I also tried using CSS to make the top pane invisible, but that doesn't seem to do anything at all.

Here's some code of that:

        pn_middle.setStyle("-fx-background-color: rgba(128, 128, 128, 0);");

        try {
            Thread.sleep(1000); //1 sec for testing
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        pn_middle.setStyle("-fx-background-color: rgba(128, 128, 128, 1);");
1
1
9/18/2014 11:04:20 AM

Accepted Answer

Use a Timer to clock the time for which you want to hide your Pane. Try the example out, it contains a StackPane which has a Pane, colored as PINK and a Button. On the click of the Button, the Pane is hidden for 1000ms

import java.util.Timer;
import java.util.TimerTask;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class HideAndShowPane extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        StackPane stackPane = new StackPane();
        Button button = new Button("Click Me to hide Pane !");
        Pane pane = new Pane();

        button.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent event) {
                    //Hide the Pane
                    pane.setVisible(false);
                    //Schedule the Visibility for 1000ms
                    Timer timer = new Timer();
                    timer.schedule(new TimerTask() {
                          @Override
                          public void run() {
                              //Run on UI thread
                              Platform.runLater(new Runnable() {
                                @Override
                                public void run() {
                                    pane.setVisible(true);                                  
                                }
                            });
                          }
                        }, 1000);   
                }
        });

        pane.setPrefSize(200, 200);
        pane.setStyle("-fx-background-color : PINK");
        stackPane.getChildren().addAll(pane, button);
        Scene scene = new Scene(stackPane, 500, 500);
        primaryStage.setScene(scene);
        primaryStage.show();

    }

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

Using Task

You can also achieve this by using Task and Thread.sleep ad later binding the valueProperty of the Task with the visibleProperty of the Pane

button.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                //Create a Task
                Task<Boolean> task = new Task<Boolean>() {
                    @Override
                    protected Boolean call() throws Exception {
                        try {
                            //Invisible for 1000ms
                            Thread.sleep(1000);
                        }
                        catch (InterruptedException e) {
                            return Boolean.FALSE;
                        }
                        return Boolean.TRUE;
                    }
                };
                //Start the Task
                new Thread(task).start();
                //Bind the visibility with Task Value
                pane.visibleProperty().bind(task.valueProperty());
         }
});

Without creating any new Threads

Thanks to Tomas Mikula's answer, this can also be achieved without creating any new Thread. Using a combination of Timeline, KeyFrames and KeyValue

button.setOnAction(new EventHandler<ActionEvent>() {
    @Override
    public void handle(ActionEvent event) {
        pane.setVisible(false);
        Timeline timeline = new Timeline();
        timeline.getKeyFrames().add(
                new KeyFrame(Duration.millis(1000), 
                        new KeyValue(pane.visibleProperty(), true)));
        timeline.play();
    }
});
0
5/23/2017 11:57:17 AM

If you use JavaFX 8, here is a solution using a timer from ReactFX. Unlike @ItachiUchiha's solution, it does not create any new threads.

import java.time.Duration;
import org.reactfx.util.FxTimer;

button.setOnAction(event -> {
    pane.setVisible(false);
    FXTimer.runLater(Duration.ofMillis(1000), () -> pane.setVisible(false));
});

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon