My scene consists only of an ImageView, displaying an image. I would like to fade the image to black (assigned color of the scene), then after some time, fade from black to the image again. I found the FadeTransition very fitting for this purpose. This is a piece of my code:
// fade to black transition
FadeTransition ft1 = new FadeTransition(Duration.millis(2000), myImageView);
ft1.setFromValue(1.0);
ft1.setToValue(0.0);
ft1.play();
// fade from black transition
FadeTransition ft2 = new FadeTransition(Duration.millis(2000), myImageView);
ft2.setFromValue(0.0);
ft2.setToValue(1.0);
ft2.play();
My problem is that ft1.play()
is asynchronous, so the code below will start being executed before ft1.play()
is exited. As the result I see only the second transition. How can I wait for the first transition to end and then to launch the second transition? I cannot put the thread to sleep in between because it's the main javafx thread (tried and didn't work).
I tried using the onFinishedProperty() method with the combination of a busy-waiting on a flag, but I get stuck in the while loop forever. Here is my code for that:
boolean isTransitionPlaying;
FadeTransition ft = new FadeTransition(Duration.millis(2000), iv);
ft.setFromValue(1.0);
ft.setToValue(0.0);
ft.onFinishedProperty().set(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
transitionPlaying = false;
}
});
transitionPlaying = true;
ft.play();
while (transitionPlaying == true)
{
// busy wait
System.out.println("still waiting...");
}
FadeTransition ft2 = new FadeTransition(Duration.millis(2000), iv);
ft2.setFromValue(0.0);
ft2.setToValue(1.0);
ft2.play();
How is waiting done properly? Thank you
Ok if your ft2
is the reflective animation of ft1
then do
ft1.setAutoReverse(true);
ft1.setCycleCount(1);
// Or
// ft1.setCycleCount(Timeline.INDEFINITE);
// to loop infinitely (blinking effect) until stop()
and you don't ft2
. If you still need ft2
to play after ft1
then
ft1.setOnFinished(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
ft2.play();
}
});
Busy waiting (or even Thread.sleep) on the JavaFX application thread is always a bad idea - you tie up the thread which handles the UI processing so your transitions, as well as the rest of your UI, is never updated - effectively freezing your app UI for the duration of the busy wait. For a responsive UI, you need to run your logic on the FX application thread as quickly as possible, then let the thread go so the rest of the JavaFX system can get on with it's processing. This is why the transitions have async callbacks - which, once you get used to them, are a very natural way of developing.
In addition to Uluk's solutions (which are great), you could also look at the SequentialTransition class for handling assistance in performing transitions in sequence. Note that if you want to take an action after the SequentialTransition has completed, you will still want to add an onFinished handler to the SequentialTransition to take action at that time.
I had problem where other code was doing some calculations and I wanted to run Animations in JavaFX app, but needed to make other code to wait for animation to finish. I wasn't able to tell this other code when animation has finished, so I have created method for playing Animation and then waiting for it to finish:
private synchronized void playAnimationAndWaitForFinish(final Animation animation) {
if (Platform.isFxApplicationThread()) {
throw new IllegalThreadStateException("Cannot be executed on main JavaFX thread");
}
final Thread currentThread = Thread.currentThread();
final EventHandler<ActionEvent> originalOnFinished = animation.getOnFinished();
animation.setOnFinished(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
if (originalOnFinished != null) {
originalOnFinished.handle(event);
}
synchronized (currentThread) {
currentThread.notify();
}
}
});
Platform.runLater(new Runnable() {
@Override
public void run() {
animation.play();
}
});
synchronized (currentThread) {
try {
currentThread.wait();
} catch (InterruptedException ex) {
//somebody interrupted me, OK
}
}
}
It is required that this method is not invoked in main JavaFX thread, otherwise, it works for me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With