Tuesday Feb 26, 2013

Managing Multiple Screens in JavaFX. (Part II)

After finishing with my first application (previous blog), I moved to my second talk I was delivering at JavaOne 2012. Now I was looking to build another UI application, for a small screen and constrained devices. I was looking into having multiple screens, but with very few UI components; I just needed to collect data from the web and displayed it. Looking at my previous framework it wasn't a good fit for this new scenario, and of course there isn't a unique solution for all applications. This is what I was trying to achieve:

  • Build an application for a city information app.

  • An application where you can explore the city's places.

  • Or you can check the map for places of interests.

  • Check the weather

  • Or even change the city

I wanted to build a more dynamic application, where screens just slide in and out... from top, bottom, right and left, like the red arrows implies. I decided to use a technique commonly used in game development, where there is a big background image, and we have a view port, like a small window, and it's by moving this window around that we get the illusion of screen changes. Notice that having a wide background picture create a great navigation effect!

    

  

Points to consider:

  • For this application I used NetBeans and JavaFX SceneBuilder, which are my favorite tools.

  • A very important consideration, from my point of view, is to have a good long background image. This will give you a nice navigation effect without any extra programming cost. It just looks good.

  • Only one big screen is designed in Scene Builder, one fxml file and one controller class. Very simple!

  • Think out of the box, your application doesn't always have to have conventional buttons, labels and other components. Navigation doesn't need to be in one direction!. If you design your UI interface correctly, the user will intuitively navigate through it without any problem! Nice looking and modern interfaces doesn't mean it will be difficult to use.

  • Customize your application using CSS. This application uses CSS heavily, giving a nice and unique touch.


    An example of the semi-transparent gray Panel areas styling looks like this:


       .my-gradientpane {
         -fx-background-radius: 10;
         -fx-background-color:
                radial-gradient(radius 100%,
                                 derive(-fx-base,-60%),
                                 derive(-fx-base,-80%)),
                derive(-fx-base,-40%),
                radial-gradient(radius 100%,
                                 derive(-fx-base,-60%),
                                 derive(-fx-base,-80%));
         -fx-background-insets: 0,1,2;
       }


    Or customizing your ChoiceBox could be something like this:



       .choice-box {
           -fx-background-color:
                  radial-gradient(radius 100%,
                                  derive(-fx-base,-60%),
                                  derive(-fx-base,-80%)),
                  derive(-fx-base,-40%),
                  radial-gradient(radius 100%,
                                  derive(-fx-base,-60%),
                                  derive(-fx-base,-80%));
           -fx-background-insets: 0 0 -1 0, 0, 1, 2;
           -fx-background-radius: 25, 25, 24;
           -fx-padding: 0.0em 0.5em 0.0em 0.0em;
           -fx-alignment: CENTER;
           -fx-content-display: LEFT;
       }


    You can find more detailed information about CSS here.

  • The viewport in my application was simply a container; in this case a Panel. This panel was smaller than the image in the background, it was just the screen's size. The rest of the screens were just not visible.

  • Moving around screens is easy. All the screens have the same width and height, so only a simple TranslateTransition was required here. A sample of this:



      ...
         @FXML
         private void showPlaces(MouseEvent event) {
            moveScreen(0, -MyEmbeddedApp.DEVICE_HEIGHT);
         }
     
         @FXML
         private void showWeather(MouseEvent event) {
            moveScreen(MyEmbeddedApp.DEVICE_WIDTH, 0);
         }
     
         private void moveScreen(int toX, int toY) {
            TranslateTransition moveMe = TranslateTransitionBuilder.
                     create().
                     toX(toX).
                     toY(toY).
                     duration(Duration.seconds(0.5)).
                     node(pane).
                     build();
                     moveMe.play();
         }
      ...


    The annotation @FXML in front of the showPlaces and showWeather methods is to be able to bind these methods to the UI components in your fxml code. More information about this can be found here.

This concludes this second part of how to manage applications with multiple screens using JavaFX. As you can see, there isn't a one-size-fits-all solution, but it's definitely a lot of fun when you need to design your UI interfaces. Have fun, design, think out of the box, and make the life of the user a bit easier and more enjoyable.

You can also see a related video I've created on our YouTube Java Channel, so you can see these applications live.

Thursday Feb 14, 2013

Manejando Multiples Pantallas en JavaFX (Parte I)

(English version)

Una de las mejores cosas de mi trabajo es que tengo la oportunidad de escribir código y jugar con las últimas technologias. He sido desarrolladora de JavaFX ya por varios años y he creado todo tipo de demostraciones. El año pasado me encontré con un problema que algunos de ustedes pueden de estar teniendo hoy en dia: Como navigar entre pantallas y como manejar fácilmente el stack the pantallas en nuestro scene graph? Esta es la razón por al cual me he decidido a escribir este blog y compartir con ustedes este pequeno framework que escribi para mi aplicacion.

Para JavaOne 2012 decidí crear una aplicacion para un casino, y necesitaría una pantalla diferente para cada juego:

Crear las pantallas fue la parte mas fácil: Utilizé NetBeans y JavaFX Scene Builder.


Para NetBeans hay varias opciones:

  • Puedes crear New Project, y seleccionar JavaFX FXML Application. Esta opción genera un projecto que contiene 3 archivos: un archivo fxml, una clase controlladora, y una clase main. El archivo fxml es donde todos los componentes the la interfaz gráfica con definidos. El controlador, tiene la injeccion de los elementos fxml junto con algunos métodos utilizados por dicha interfaz gráfica. Finalmente, la clase main carga el archivo fxml, y comienza la ejecucion de la applicación.

  • La segunda opición es a partir de un projecto existente. Puedes hacer click derecho en el projecto y seleccionar Add Empty fxml file. Una pantalla te preguntara si deseas la creación del controllador asociado con el nuevo archivo fxml, en mi opinion, si se debe de crear esta clase controladora y mas tarde en este blog miraremos por que. A diferencia de la opción anterior, en este caso no se crea una clase main, y en algún lugar de nuestro código estamos a cargo de cargar y desplegar los componentes gráficos creados en el archivo fxml.


A partir del fxml inicial, podemos editar fácilmente este archivo usando JavaFX Scene Builder. Es verdaderamente fácil de usar, y puedes encontrar tutoriales hacerca de esto aqui.

Ahora, todo parece muy simple, verdad? Bueno, no tanto. A medida de que vamos creando las pantallas, nos encontraremos que tenemos un montón de archivos fxml y un montón de clases controladoras, una por cada pantalla creada. Esto parece rasonable, ya que no queremos por ningún motivo tener la definición de todas las pantallas en un solo archivo fxml. Pero como manejarlas?


Miremos que debemos de tener en cuenta:

  • Lo primero que se nos viene a la cabeza es utilizar un StackPane, correcto? Ponemos todas las pantallas en este Stack, una encima de la otra, y la que este en el tope del Stack es la que sería desplegada. Para cambiar de pantalla, sería tan fácil como cambiar de posición las pantallas en dicho Stack. Esto, aunque parece simple, no sería buena idea, ya que el rendimiento de la aplicación se veria seriamente afectado. El scene graph sería inmenso, y cargado de componentes gráficos que no son nisiquiera visibles. Uno de las primeras reglas en JavaFX para tener buen rendimiento es mantener el scene graph pequeño.

  • Definitivamente deseamos mantener archivos fxml separados, uno por cada pantalla. El diseño y el mantenimiento de estos serán muchisimo mas fácil de esta manera.

  • También tiene sentido tener un controlador por cada pantalla. De nuevo, queremos mantener separados no sólo los componentes gráficos sino tambien los comportamientos asociados a estos.

  • Necesitamos definir una navegacion limpia y fácil entre las pantallas.

  • Una vez más, MANTIENE el scene graph pequeño!

Entonces, que podríamos hacer?

  • StackPane sigue siendo una opción excelente como contenedor, simplemente se debe manejar de forma apropiada. En el framework que you cree, el stack pane sólo posee una pantalla en el stack al tiempo. Para mi aplicación yo opté por una imagen común como fondo de la aplicación, asi las transiciones entre pantallas serían mas fáciles. Para pasar a una nueva pantalla, una serie de animaciones tienen lugar. Por simplicidad de este framework utilicé "fade transitions", pero puedes cambiar y utilizar la transición que desees.
    La imagen de fondo de la applicación siempre permanece en el scene graph, y es visible todo el tiempo. Para movernos a una nueva pantalla, la primera transicion 'fade' tiene lugar, haciendo desaparecer los componentes graficos de la pantalla actual. El framework utiliza un EventHandler, el cual será notificado cuando esta transición 'fade' termine. Cuando esto sucede, pasamos a retirar los components de la pantalla que estaba siendo desplegada y que en este momento ya son invisibles. Luego adicionamos los componentes gráphicos de la nueva pantalla (pantalla a ser desplegada) que por defecto son invisibles, pasando luego a ejecutar una nueva transicion en la que hacemos visibles todos sus componentes. De esta manera, solo una pantalla esta cargada en el scene graph y no se vera afectada el buen rendimiento de la aplicación. Aqui estan los pasos a seguir:



    • Mostrar la pantalla principal

    • El usuario selecciona un juego

    • La pantalla actual empieza a desaparecer (transición). Al terminar, esta es retirada el scene graph y la nueva pantalla comienza a hacerce visible.

    • Hasta que finalmente la nueva pantalla es completamente visible.

    • El StackPane termina tan sólo con una pantalla en su scene graph.
    • Con este método, se puede especificar cualquier transicion deseada entre pantallas. Estas pueden entrar de arriba hacia abajo, or entrar horizontalmente por uno de los lados: puedes implementar la animación que desees.


Ahora miremos el código:

  1. Primero, todas las pantallas necesitan saber sobre su padre, en nuestro caso fue la pantalla main, ya que necesitamos poder regresar al menu principal una vez el usuario termine de jugar, o simplemente porque el usuario desee seleccionar un nuevo juego. Para esto necesitaremos una interfaz común (ControlledScreen), con un método para la injección del padre(setScreenParent).


      public interface ControlledScreen {

         //This method will allow the injection of the Parent ScreenPane
         public void setScreenParent(ScreensController screenPage);
      }

  2. Por cada pantalla mantenemos un archivo fxml separado, al igual que una clase controladora, como lo mensionamos al principio de este blog. Cada controlador debe implementar ControlledScreen, para que todos ellos compartan el mismo tipo, y podamos mas tarde asociara el padre a cada pantalla.


      public class Screen1Controller implements Initializable,
                                                ControlledScreen {

         ScreensController myController;

         @Override
         public void initialize(URL url, ResourceBundle rb) {
             // TODO
         }

         public void setScreenParent(ScreensController screenParent){
            myController = screenParent;
         }


         //any required method here
      }


    • Ahora que cada controlador tiene la referencia de su padre, podemos pasar a definir los métodos que realizarán la navegación. Por ejemplo, si deseamos regresar a la pantalla principal de uno de los juegos, debemos ejecutar el siguiente método:


         @FXML
         private void goToMain(ActionEvent event){
           myController.setScreen(ScreensFramework.MAIN_SCREEN);
         }

  3. Necesitamos una nueva clase (ScreensController) para majenar las pantallas:

    • Esta clase de heredar StackPane, ya que parece ser la opción mas adecuada para nuestro escenario.


         public class ScreensController extends StackPane {


    • ScreensController contiene un HashMap llamado screens. Esta collección contiene parejas construídas por el identificador de la pantalla junto al nodo que representa la raiz de su scene graph.


         private HashMap<String, Node> screens = new HashMap<>();


    • Esta clase debe definir métodos para addicionar, cargar y mostrar la pantalla adecuada:

      • addScreen(String id, Node screen) adiciona una pareja (id, screen) al HashMap screens.


           public void addScreen(String name, Node screen) {
               screens.put(name, screen);
           }

      • loadScreen(String id, String resource) Este método carga el archivo fxml especificado por resource, y obtiene el nodo raiz para you pantalla. También podemos obtener el controlador asociado con la pantalla, esto nos permitirá configurar el padre. Esto es posible ya que todos los controladores comparten el mismo tipo ControlledScreen.
        Finalmente, la pantalla es adicionada al hash map llamado screens. Como se puede observar en el código, el archivo fxml que se ha cargado, aun no se ha adicionado al scene graph, osea que aun no es desplegado por JavaFX.


           public boolean loadScreen(String name, String resource) {
             try {
               FXMLLoader myLoader = new
                       FXMLLoader(getClass().getResource(resource));
               Parent loadScreen = (Parent) myLoader.load();
               ControlledScreen myScreenControler =
                      ((ControlledScreen) myLoader.getController());
               myScreenControler.setScreenParent(this);
               addScreen(name, loadScreen);

               return true;
             }catch(Exception e) {
               System.out.println(e.getMessage());
               return false;
             }
           }

      • setScreen(String screenName). Este método muestra la pantalla especificada con el identificador dado.

        • Primero verificamos si la panatalla reconocida por ese identificador ha sido cargada previamente.

        • También tenemos que chequear si hay ya una pantalla desplegada (necesitamos entonces hacer transiciones entre pantallas), o si esta es la primera pantalla a ser mostrada (simplemente se muestra la pantalla).

        • Si ya existe una pantalla, ejecutamos la transicion y definimos el eventHandler para que se haga cargo de la ejecución, una vez termine esta transición.

        • Una vez la antigua pantalla se hace invisible, se remueve del scene graph, y se adiciona la nueva. De nuevo, una animación es realizada para mostrar la nueva pantalla.


           public boolean setScreen(final String name) {

             if(screens.get(name) != null) { //screen loaded
               final DoubleProperty opacity = opacityProperty();

               //Is there is more than one screen
               if(!getChildren().isEmpty()){
                 Timeline fade = new Timeline(
                   new KeyFrame(Duration.ZERO,
                                new KeyValue(opacity,1.0)),
                   new KeyFrame(new Duration(1000),

                       new EventHandler() {

                         @Override
                         public void handle(ActionEvent t) {
                           //remove displayed screen
                           getChildren().remove(0);
                           //add new screen
                           getChildren().add(0, screens.get(name));
                           Timeline fadeIn = new Timeline(
                               new KeyFrame(Duration.ZERO,
                                      new KeyValue(opacity, 0.0)),
                               new KeyFrame(new Duration(800),
                                      new KeyValue(opacity, 1.0)));
                           fadeIn.play();

                         }
                       }, new KeyValue(opacity, 0.0)));
                 fade.play();
               } else {
                 //no one else been displayed, then just show
                 setOpacity(0.0);
                 getChildren().add(screens.get(name));
                 Timeline fadeIn = new Timeline(
                     new KeyFrame(Duration.ZERO,
                                  new KeyValue(opacity, 0.0)),
                     new KeyFrame(new Duration(2500),
                                  new KeyValue(opacity, 1.0)));
                 fadeIn.play();
               }
               return true;
             } else {
                 System.out.println("screen hasn't been loaded!\n");
                 return false;
           }
          

    • Tambien necesitamos un método unloadScreen(String name). Este simplemente remueve la pantalla de nuestra hash map, reportando el status de esta operación.


         public boolean unloadScreen(String name) {
           if(screens.remove(name) == null) {
             System.out.println("Screen didn't exist");
             return false;
           } else {
             return true;
           }
         }


  4. Ahora lo único que necesitamos es comenzar a utilizar el framework. Aqui esta una pequeña parte de código que muestra como hacerlo.


       public class ScreensFramework extends Application {

         public static final String MAIN_SCREEN = "main";
         public static final String MAIN_SCREEN_FXML = "main.fxml";
         public static final String POKER_SCREEN = "poker";
         public static final String POKER_SCREEN_FXML =
                                              "poker.fxml";
         public static final String ROULETTE_SCREEN = "roulette";
         public static final String ROULETTE_SCREEN_FXML =
                                              "roulette.fxml";

         @Override
         public void start(Stage primaryStage) {

           ScreensController mainContainer = new ScreensController();
           mainContainer.loadScreen(ScreensFramework.MAIN_SCREEN,
                                ScreensFramework.MAIN_SCREEN_FXML);

           mainContainer.loadScreen(ScreensFramework.POKER_SCREEN,
                                ScreensFramework.POKER_SCREEN_FXML);

           mainContainer.loadScreen(ScreensFramework.ROULETTE_SCREEN,
                                ScreensFramework.ROULETTE_SCREEN_FXML);


           mainContainer.setScreen(ScreensFramework.MAIN_SCREEN);

           Group root = new Group();
           root.getChildren().addAll(mainContainer);
           Scene scene = new Scene(root);
           primaryStage.setScene(scene);
           primaryStage.show();
         }
       ...


Este framework fue de bastante ayuda para la creación de mi aplicación y espero que también sea de utilidad para usteded. Pueden encontrar la implementación de este framework, junto con tres clases para verificar que todo funcione en este link.

Tambien hay un video asociado a este blog que pueden encontrar aqui.

Friday Feb 08, 2013

Managing Multiple Screens in JavaFX. (Part I)

(Versión en Español)

One of the best things about my job is that it give me the opportunity to write code and play with the latest technologies. As a JavaFX developer I've created all sort of demos, and last year I faced an issue many developer might be facing today: How to transition between screens and how to manage the screen's stack? That is the reason why I've decided to write about my experiences with it, and to share with you a small framework I wrote for that.

For JavaOne 2012 I decided to create a Casino demo, and I needed to have multiple screens, one for each game:

Creating the screens was the easiest part: I used NetBeans in conjunction with JavaFX Scene Builder.


From NetBeans you have multiple options:

  • You can create a New Project, and select JavaFX FXML Application. This option will generate a project containing three files: a fxml file, a java controller and a main class. The fxml file is where all your UI components will be define. The java controller class has the fxml elements injections along with some methods used by the UI. Finally, the main class loads the fxml file, and start the execution of your application.

  • Second option is from an existent project. You can right click your project and select Add Empty fxml file. You will be prompted to acknowledge the creation of a controller associated with this new fxml file, which I recommend to do!. Different from the previous option, in this case no main class will be created, and somewhere in your code you are in charge of loading and displaying your fxml elements.


Once you have the initial fxml file, you can edit it using the JavaFX Scene Builder. It's really easy to use, and you can find some tutorials about it here.

Now, things seem to be really easy, right? Well, not quite. As you start creating your screens, you find yourself with a bunch of fxml files and controllers, one per each screen. This seems reasonable, as we don't want to place all the screens in a single fxml file, but how to manage them?


Here are a few things to keep in mind:

  • StackPane seems to be the first option you can thing of, right? Just have all the screens stacked one on top of each other, and the one on top gets displayed. Changing screens will be just switching places in the stack. This is not a very good idea, as we might be encountering some performance issues. The scene graph will be huge, and loaded with a lot of UI components that are not even visible. Keeping your scene graph small is the first trick for a good performance in your JavaFX application.

  • We definitely want to keep separate fxml for each screen, designing and maintaining the screens will be a much easier job.

  • One controller per screen also makes sense. One more time, we want to maintain separate screens elements and behaviors.

  • We need to define clean and easy navigation among the screens.

  • Once again, we need to keep our scene graph small.

Then, what should we do?

  • StackPane still is a great option for the container, we just need to manage it properly. In the proposed framework, we only have one screen stacked at a time. In our design, I opted for a common background, so the transition between screens was really smooth. When we are transitioning to a new screen, I play a couple of animations. As I've mentioned before I just used fade transitions, but you can customize your framework and have any transition you want. The background always stays there, and the first fade transition takes place, fading out the current screen. The framework implements an EventHandler, so we can listen when this fading process ends, as we need to remove the already invisible screen, and show the new one by adding it to the scene graph and playing a fade-in animation. Only one screen is uploaded in the scene graph. This allows us to keep it as light as possible, and we don't have a negative impact in performance. Here are the steps:



    • Display main screen

    • User select a game

    • The current screen starts to fade out. Once it finishes, the old screen gets remove from the scene graph and the new screen start to fade in.

    • Now the new screen is totally visible (opacity 1), and our graph stays light.

    • The StackPane finishes with only one screen in its tree.
    • With this approach, you can define any transition between the screens. You can drop the new screen from the top, or you can slide in the new screen from any side; you can use any animation you can think of.


Now, lets have a look at the code:

  1. First, all the screens need to know about their parent, in our case the main screen, as we need to be able to return to the main menu once we finish playing, perhaps to choose a different game. A common interface will do the trick (ControlledScreen), with a method for parent injection (setScreenParent), so we can initialize each screen's parent.


      public interface ControlledScreen {

         //This method will allow the injection of the Parent ScreenPane
         public void setScreenParent(ScreensController screenPage);
      }

  2. For each screen, we keep a separate fxml file, and a controller java file, as we mentioned at the beginning of the blog. Each controller class should implement the ControlledScreen, so all of them shared the type, and we can set the screen's parent later on.


      public class Screen1Controller implements Initializable,
                                                ControlledScreen {

         ScreensController myController;

         @Override
         public void initialize(URL url, ResourceBundle rb) {
             // TODO
         }

         public void setScreenParent(ScreensController screenParent){
            myController = screenParent;
         }


         //any required method here
      }


    • Now as each controller class has a reference to the parent screen, you can define methods to perform the correct navigation. For example if you want to go back to main screen from one of the games, you just need to call somewhere the following method.


         @FXML
         private void goToMain(ActionEvent event){
           myController.setScreen(ScreensFramework.MAIN_SCREEN);
         }

  3. We need a new class (ScreensController) for managing the screens:

    • This class will extend StackPane, as it seems to be a perfect choice for our scenario.


         public class ScreensController extends StackPane {


    • ScreensController will have a HashMap called screens. This collection contains pairs formed by the screen's ID and the node representing the top of the screen's scene graph.


         private HashMap<String, Node> screens = new HashMap<>();


    • This class has methods for adding, loading and setting the screens:

      • addScreen(String id, Node screen) add the pair (id, screen) to the HashMap screens.


           public void addScreen(String name, Node screen) {
               screens.put(name, screen);
           }

      • loadScreen(String id, String resource) This method loads the fxml file specified by resource, and it gets the top Node for the screen. We can also get the controller associated to this screen, which allows us to set the parent for the screen, as all the controllers shared the common type ControlledScreen. Finally the screen is added to the screens hash map. As you can see from the code, the loaded fxml file, doesn't get added to the scene graph, so the loaded screen doesn't get displayed or loaded to the screen.


           public boolean loadScreen(String name, String resource) {
             try {
               FXMLLoader myLoader = new
                       FXMLLoader(getClass().getResource(resource));
               Parent loadScreen = (Parent) myLoader.load();
               ControlledScreen myScreenControler =
                      ((ControlledScreen) myLoader.getController());
               myScreenControler.setScreenParent(this);
               addScreen(name, loadScreen);

               return true;
             }catch(Exception e) {
               System.out.println(e.getMessage());
               return false;
             }
           }

      • setScreen(String screenName). This method displays a screen with a given screen name.

        • First the method verifies that the screen has been previously loaded.

        • We check if there is already a screen been displayed, so we need to play the screen transition sequence. If there isn't any screen, we just add it to the graph and perform a nice fade-in animation.

        • If there is a screen already been displayed, we play an animation to fade out the current screen, and we defined an eventHandler to handle execution after this.

        • Once the screen is invisible, we remove it from the graph, and we add the new screen. Again, a nice animation is played to show the new screen.


           public boolean setScreen(final String name) {

             if(screens.get(name) != null) { //screen loaded
               final DoubleProperty opacity = opacityProperty();

               //Is there is more than one screen
               if(!getChildren().isEmpty()){
                 Timeline fade = new Timeline(
                   new KeyFrame(Duration.ZERO,
                                new KeyValue(opacity,1.0)),
                   new KeyFrame(new Duration(1000),

                       new EventHandler() {

                         @Override
                         public void handle(ActionEvent t) {
                           //remove displayed screen
                           getChildren().remove(0);
                           //add new screen
                           getChildren().add(0, screens.get(name));
                           Timeline fadeIn = new Timeline(
                               new KeyFrame(Duration.ZERO,
                                      new KeyValue(opacity, 0.0)),
                               new KeyFrame(new Duration(800),
                                      new KeyValue(opacity, 1.0)));
                           fadeIn.play();

                         }
                       }, new KeyValue(opacity, 0.0)));
                 fade.play();
               } else {
                 //no one else been displayed, then just show
                 setOpacity(0.0);
                 getChildren().add(screens.get(name));
                 Timeline fadeIn = new Timeline(
                     new KeyFrame(Duration.ZERO,
                                  new KeyValue(opacity, 0.0)),
                     new KeyFrame(new Duration(2500),
                                  new KeyValue(opacity, 1.0)));
                 fadeIn.play();
               }
               return true;
             } else {
                 System.out.println("screen hasn't been loaded!\n");
                 return false;
           }
          

    • We also have an unloadScreen(String name) method, that simple removes the screen from our hashmap, and report the status of this operation.


         public boolean unloadScreen(String name) {
           if(screens.remove(name) == null) {
             System.out.println("Screen didn't exist");
             return false;
           } else {
             return true;
           }
         }


  4. Now all we have to do is start using the framework. Here I show a small piece of code where you load the screens, and show the main one.


       public class ScreensFramework extends Application {

         public static final String MAIN_SCREEN = "main";
         public static final String MAIN_SCREEN_FXML = "main.fxml";
         public static final String POKER_SCREEN = "poker";
         public static final String POKER_SCREEN_FXML =
                                              "poker.fxml";
         public static final String ROULETTE_SCREEN = "roulette";
         public static final String ROULETTE_SCREEN_FXML =
                                              "roulette.fxml";

         @Override
         public void start(Stage primaryStage) {

           ScreensController mainContainer = new ScreensController();
           mainContainer.loadScreen(ScreensFramework.MAIN_SCREEN,
                                ScreensFramework.MAIN_SCREEN_FXML);

           mainContainer.loadScreen(ScreensFramework.POKER_SCREEN,
                                ScreensFramework.POKER_SCREEN_FXML);

           mainContainer.loadScreen(ScreensFramework.ROULETTE_SCREEN,
                                ScreensFramework.ROULETTE_SCREEN_FXML);


           mainContainer.setScreen(ScreensFramework.MAIN_SCREEN);

           Group root = new Group();
           root.getChildren().addAll(mainContainer);
           Scene scene = new Scene(root);
           primaryStage.setScene(scene);
           primaryStage.show();
         }
       ...


I found this framework very useful for my application, and I hope this will be valuable for you too. You can find a full implementation with three testing screens available following this link.

You can also see a related video I've created on our YouTube Java Channel, so you can see this application live.

About

Angela Caicedo

Search

Categories
Archives
« February 2013 »
SunMonTueWedThuFriSat
     
1
2
3
4
5
6
7
9
10
11
12
13
15
16
17
18
19
20
21
22
23
24
25
27
28
  
       
Today