This discussion is archived
9 Replies Latest reply: Mar 16, 2012 7:41 AM by 907516 RSS

transition between scenes

907516 Newbie
Currently Being Moderated
Hi! Is it possible to apply a transition effect during a scene swap within a stage?
Stage stage = new Stage();

stage.setScene(new SceneA());
// I'd like to show a transition effect during this swap
stage.setScene(new SceneB());
Edited by: redcloud on Mar 12, 2012 9:33 PM
  • 1. Re: transition between scenes
    JohnHendrikx Pro
    Currently Being Moderated
    Put both scenes in a StackPane and use the StackPane as the scene root.

    Then do something like this:
    StackPane stackPane = new StackPane();
    
    stackPane.add(oldScene);
    stackPane.add(newScene);
    
    oldScene.setOpacity(1.0);
    newScene.setOpacity(0.0);
    
    scene.setRoot(stackPane);
    
    Timeline timeline = new Timeline(
      new KeyFrame(Duration.seconds(0), new KeyValue(oldScene.opacityProperty(), 1.0), new KeyValue(newScene.opacityProperty(), 0.0)),
      new KeyFrame(Duration.seconds(2), new KeyValue(oldScene.opacityProperty(), 0.0), new KeyValue(newScene.opacityProperty(), 1.0))
    };
    
    timeline.play();
  • 2. Re: transition between scenes
    907516 Newbie
    Currently Being Moderated
    It seems impossible to add a Scene to a StackPane...
  • 3. Re: transition between scenes
    JohnHendrikx Pro
    Currently Being Moderated
    The name of the variables I use is confusing, I don't mean the Scene, I mean the root of the Scene.
  • 4. Re: transition between scenes
    shakir.gusaroff Expert
    Currently Being Moderated
    Hi. Take a look at this example:
    import javafx.application.Application;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.scene.Group;
    import javafx.scene.Scene;
    import javafx.scene.layout.*;
    import javafx.scene.control.*;
    import javafx.stage.Stage;
    import javafx.animation.*;
    import javafx.scene.layout.VBoxBuilder;
    import javafx.scene.text.TextBuilder;
    import javafx.util.*;
    
    public class AnimatedScenes extends Application {
    
        VBox page1 = null;
        VBox page2 = null;
        Timeline timeline1 = null;
        Timeline timeline2 = null;
    
        /**
         * @param args the command line arguments
         */
        public static void main(String[] args) {
            Application.launch(args);
        }
    
        @Override
        public void start(final Stage primaryStage) {
    
    
            primaryStage.setTitle("Hello World");
    
            final Group root = new Group();
            final Scene scene = new Scene(root, 300, 250);
            page1 = VBoxBuilder.create()
                    .spacing(10)
                    .children(TextBuilder.create()
                    .text("Home page").build(),
                    ButtonBuilder.create()
                    .text("Login")
                    .onAction(new EventHandler<ActionEvent>() {
    
                @Override
                public void handle(ActionEvent e) {
                    root.getChildren().remove(page1);
                    timeline1.play();
                    root.getChildren().add(page2);
                }
            }).build())
            .build();
    
    
    
            page2 = VBoxBuilder.create()
                    .spacing(10)
                    .children(TextFieldBuilder.create()
                    .text("")
                    .build(),
                    ButtonBuilder.create()
                    .text("Go to home page")
                    .onAction(new EventHandler<ActionEvent>() {
    
                @Override
                public void handle(ActionEvent e) {
                    root.getChildren().remove(page2);
                    timeline2.play();
                    root.getChildren().add(page1);
                }
            }).build()).build();
    
    
            root.getChildren().add(page1);
    
            timeline1 = new Timeline(
                    new KeyFrame(Duration.seconds(0), new KeyValue(page2.opacityProperty(), 0.0)),
                    new KeyFrame(Duration.seconds(3), new KeyValue(page2.opacityProperty(), 1.0)));
    
    
    
            timeline2 = new Timeline(
                    new KeyFrame(Duration.seconds(0), new KeyValue(page1.opacityProperty(), 0.0)),
                    new KeyFrame(Duration.seconds(3), new KeyValue(page1.opacityProperty(), 1.0)));
    
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    }
  • 5. Re: transition between scenes
    JohnHendrikx Pro
    Currently Being Moderated
    I meant more like this. With a StackPane you can get the transition to happen with both pages temporarily visible at once in some fashion (in this case a cross fade).
    import javafx.animation.KeyFrame;
    import javafx.animation.KeyValue;
    import javafx.animation.Timeline;
    import javafx.application.Application;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.scene.control.ButtonBuilder;
    import javafx.scene.control.TextFieldBuilder;
    import javafx.scene.layout.StackPane;
    import javafx.scene.layout.VBox;
    import javafx.scene.layout.VBoxBuilder;
    import javafx.scene.text.TextBuilder;
    import javafx.stage.Stage;
    import javafx.util.Duration;
    
    public class AnimatedScenes extends Application {
    
        StackPane stackPane = new StackPane();
        VBox page1 = null;
        VBox page2 = null;
    
        /**
         * @param args the command line arguments
         */
        public static void main(String[] args) {
            Application.launch(args);
        }
    
        @Override
        public void start(final Stage primaryStage) {
    
            primaryStage.setTitle("Hello World");
    
            final Scene scene = new Scene(stackPane, 300, 250);
    
            page1 = VBoxBuilder.create()
                    .spacing(10)
                    .children(TextBuilder.create()
                    .text("Home page").build(),
                    ButtonBuilder.create()
                    .text("Login")
                    .onAction(new EventHandler<ActionEvent>() {
    
                @Override
                public void handle(ActionEvent e) {
                  switchPage(page2);
                }
            }).build())
            .build();
    
            stackPane.getChildren().add(page1);
    
            page2 = VBoxBuilder.create()
                    .spacing(10)
                    .children(TextFieldBuilder.create()
                    .text("")
                    .build(),
                    ButtonBuilder.create()
                    .text("Go to home page")
                    .onAction(new EventHandler<ActionEvent>() {
    
                @Override
                public void handle(ActionEvent e) {
                    switchPage(page1);
                }
            }).build()).build();
    
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        private void switchPage(Parent newPage) {
          stackPane.getChildren().add(newPage);
    
          EventHandler<ActionEvent> finished = new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
              stackPane.getChildren().remove(0);
            }
          };
    
          final Timeline switchPage = new Timeline(
            new KeyFrame(Duration.seconds(0), new KeyValue(stackPane.getChildren().get(1).opacityProperty(), 0.0), new KeyValue(stackPane.getChildren().get(0).opacityProperty(), 1.0)),
            new KeyFrame(Duration.seconds(3), finished, new KeyValue(stackPane.getChildren().get(1).opacityProperty(), 1.0), new KeyValue(stackPane.getChildren().get(0).opacityProperty(), 0.0))
          );
    
          switchPage.play();
        }
    }
  • 6. Re: transition between scenes
    907516 Newbie
    Currently Being Moderated
    Thank you all for your tips. I found this solution
    private void launchClient() {
              int stageWidth = Main.getSettings().getClientWidth();
              int stageHeight = Main.getSettings().getClientHeight();
    
              // if (stageWidth == 0 || stageHeight == 0) {
              // stageWidth =
              // }
              //
              // stage.setTitle(Constants.SHORT_TITLE);
    
              StackPane stackPane = new StackPane();
    
              Pane logoPane = new LogoPane(stage, 1280, 768);
              Pane mainPane = new MainPane(stage, 1280, 700);
    
              stackPane.getChildren().add(mainPane);
              stackPane.getChildren().add(logoPane);
    
              logoPane.setOpacity(1);
              mainPane.setOpacity(1);
    
              final Timeline timeline1 = new Timeline(new KeyFrame(Duration.seconds(0), new KeyValue(stage.opacityProperty(), 0.0)), new KeyFrame(
                        Duration.seconds(2), new KeyValue(stage.opacityProperty(), 1.0)));
    
              final TranslateTransition transition = new TranslateTransition(Duration.seconds(1), logoPane);
              transition.setFromY(0);
              transition.setToY(768);
              transition.setInterpolator(Interpolator.SPLINE(0.5, 1, 1, 0));
              transition.setDelay(Duration.seconds(1.5));
    
              final SequentialTransition st = new SequentialTransition(timeline1, transition);
    
              Scene root = new Scene(stackPane, 1280, 768, Color.BLACK);
    
              stage.setOnShown(new EventHandler<WindowEvent>() {
    
                   @Override
                   public void handle(WindowEvent arg0) {
                        st.play();
                   }
              });
              stage.setScene(root);
              stage.setResizable(false);
              stage.initStyle(StageStyle.UNDECORATED);
              stage.show();
         }
  • 7. Re: transition between scenes
    907516 Newbie
    Currently Being Moderated
    I think I've found a little issue with setOnFinished applied to a Transition.
    transition.setOnFinished(new EventHandler<ActionEvent>() {
         @Override
         public void handle(ActionEvent arg0) {
              // cpu consuming task
         }
    });
    What I'm expecting from this code is that once the transition is completed, the cpu consuming task will start.
    What I notice however is that the transition is interrupted just before the end (I mean on the gui painting side, some artifacts will remain painted). It looks like that the handle method doesn't take into account the time spent for the graphics refresh. If I remove the cpu consuming task, the transition looks good. How to solve?
  • 8. Re: transition between scenes
    jsmith Guru
    Currently Being Moderated
    If it is not already, make the cpu consuming task a Task and return from the handle method as quickly as possible, while the cpu consuming Task is executed in parallel.
    http://docs.oracle.com/javafx/2.0/api/javafx/concurrent/Task.html
  • 9. Re: transition between scenes
    907516 Newbie
    Currently Being Moderated
    It could be a good workaround but it's not acceptable for me.

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points