/ JavaFX / Responsive Design for JavaFX

Responsive Design for JavaFX

Hendrik on 2014/11/04 - 01:00 in JavaFX

Once of the new APIs that I have shown at JavaOne was ResponsiveFX that can be used to add responsive design to your JavaFX application. ResponsiveFX is an open source project maintained by Canoo and will be published to Maven Central the next days.

Responsive Design

Today software must fit a wide range of devices. When developing an application customers often want to use it on a desktop pc and on a tablet. In addition a subset of the features should be useable with a mobile phone. Oh, and maybe next year the first customers want to check information on a smart watch. Even if web apps and JavaFX applications can be distributed and used on most of this devices you can’t simply use the same UI on them.

responsive1
All these devices provide different screen sizes and resolutions. In addition the user interaction is in some parts completely different. While using a mouse and keyboard on a desktop pc you want to use touch and gestures on your mobile to navigate through the app.
One approach to handle these issues is responsive design that can be used to provide an optimal viewing experience—easy reading and navigation with a minimum of resizing, panning, and scrolling—across a wide range of devices. Responsive design was first introduced by web applications and influenced the development trends in this area. By defining different layout for specific screen sizes the fronted of a web application will look good on mostly all devices.

responsive2

ResponsiveFX

The core concept of ReponsiveFX is copied from Twitter Boostrap that provides responsive design for HTML. Boostrap provides several CSS style classes that can be used to hide or show components on different screen sizes. Here is a short overview of all the style classes:
responsive-twitter
By adding one of these style classes to a component the visibility of the component depends on the current frame size. Here is a small example how this can be used in HTML:

Responsive Design & JavaFX

By default JavaFX doesn’t provide an API for responsive design. Thankfully JavaFX supports CSS and therefore we can add this feature. This is exactly what ReponsiveFX does. By using the API you can simply use the same style classes as in HTML in your JavaFX application. To add the responsive support to an application you only need one line of Java code:


This adds the support for responsive design to the given stage. All nodes that are in this stage can now use the described style classes. Therefore you can simply do the following in Java code:


In the example a table and a list are defined that will visualize the same set of data (items). Depending on the size of the application the list or the table will be shown on screen. Here is a short video that shows the behavior:

By adding this API to your JavaFX application you will have the same possibilities as in HTML to provide responsive design.

Responsive Design & pseudo classes

By using the given classes you can hide and show components depending to the frame size in your application but often you want to show different sizes of controls depending on the screen size. Let’s think about a toolbar that should have a different size in all supported screen sizes. In HTML you would do the following:


In JavaFX this would correspond the following code snippet:


This is very bad practive because Java must handle all 4 instances in this case. Even if only one toolbar will be displayed on screen all are part of the scene graph. If you will do this with controls that contains images you will blow up your memory for example. Therefore you shouldn’t do this. I thinks it’s clear that we need a better solution and ResponsiveFX contains one :)
Next to the style classes ReponsiveFX provides pseudo classes for all supported screen sizes. Here is a list of the supported pseudo classes:

  • extreme-small-device
  • small-device
  • medium-device
  • large-device

By using this pseudo classes you can define the visualization of a node depending on the current application size. The pseudo classes will automatically be added and removed for each node inside the scene graph of a windows that is handled by the ResponsiveHandler. Thanks to this you can define the following CSS rules for a control:


In your Java code you can now define one control and set its ID to match the CSS rules:


Whenever the size of the application will change the matching pseudo class will be set to the control and the visualization of the control will change depending on the CSS attributes. By doing so you can create applications that will look different on the specified frame sizes. This will be helpful when developing applications that should work for desktop and mobile or on embedded devices. Here is a short video that shows how a responsive application might look:

Responsive Design in Java code

In addition to the shown features ReponsiveFX supports a Java API to react on responsive changes. A listener can be registered to the ResponsiveHandler and will be fired whenever the responsive types changes. By doing so you can react on changes direct in Java code. This will be helpful if you need to change anything that can’t be done by CSS. AT the moment this feature is a fast hack for JavaOne but I plan to refactor this in near future.

Where can I get it?

As said ResponsiveFX will be released in near future. I’m currently create clean modules / libraries of all the demos and examples that I showed at JavaOne. ResponsiveFX is already extracted as a stand alone library. The next days I will set up the GitHub repo and add some documentation. Once this is done I will upload the first version to Maven Central.

Additional Information

Because of a missing feature in JavaFX ReponsiveFX contains some hacks that can result in unwanted behavior. If you like the API and need responsive design in JavaFX you should vote for this issue at the JavaFX bug database.

34 POST COMMENT

Send Us A Message Here

Your email address will not be published. Required fields are marked *

34 Comments
  • 2014/11/10

    That’s really nice! If you know Bootstrap than it is very easy to understand. It is nice to see, that cool web technologies, like glyph fonts, popovers and now Bootstrap responsive, getting more and more available for JavaFX. So Oracle, please provide (official) support for Android :)

    vertex
    Reply
  • 2014/11/15

    “The pseudo classes will automatically be added and removed for each node inside the scene graph of a windows that is handled by the ResponsiveHandler.”

    Adding a pseudo (or even multiple ones) to each node in a scene graph, maybe even nodes inside skins, sounds like an expensive operation (not even thinking about listeners to keep it like that when the scene graph changes). Can’t this be avoided? If the pseudo is attached to the root node only we could still use it in selectors:

    .root:large-device #toolbar {

    }

    Werner Lehmann
    Reply
    • 2014/11/15

      Sounds like a good Idea. I will try it. Thx

      admin
      Reply
  • 2014/11/17

    We need a way to handle responsive design via FXML too…

    Reply
  • 2014/11/26

    I want to try it!!!. Do you have the release date?

    Bill
    Reply
    • 2014/12/24

      Hi,
      I finished the javadoc this week and will release it soon.

      Reply
  • 2014/12/07

    Oh this is fun… Nice work!

    Reply
  • 2015/01/07

    Hello how can i get the source?? thanks.

    Dustin
    Reply
  • 2015/02/04

    Thats a nice work. When can we expect it to be released ??
    Thanks.

    Mark
    Reply
  • 2015/02/19

    you’re going to release the code javafx finally responsive?

    Denny
    Reply
  • 2015/04/20

    Hello, this looks awesome! As someone who has done a lot of Bootstrap styling, and now into JavaFX, this is great!
    I found 0.7 on maven central, is this ready to use in production?
    I wish to see more updates on this!

    Regards

    Robin Jonsson
    Reply
    • 2015/04/20

      Hi,
      0.7 is the last version. I refactored some classes and added javadoc in my current version but I didn’t release it until know.

      Reply
  • 2015/06/09

    Hey man can you release this project?

    Juan
    Reply
  • 2015/07/22

    FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(“Sys1.fxml”));
    Parent root4 = (Parent) fxmlLoader.load();
    Stage stage = new Stage();
    ResponsiveHandler.addResponsiveToWindow(stage);
    stage.setScene(new Scene(root4));
    stage.show();

    It’s not showing effect .

    Drashti
    Reply
  • 2015/10/02

    hello , could show a complete example ? For here got errors , thank you.

    Vinicius D. Alves
    Reply
  • 2015/10/30

    Where can I get the api?

    Pranish
    Reply
  • 2015/12/08

    Can I use this API for FXML application ? Please Reply Fast

    Krunal Chaudhari
    Reply
    • 2015/12/08

      Yes you can use it in combination with FXML

      Reply
      • 2015/12/10

        Hello Sir,

        Can You Please Give me Simple Demo Using this API in FXML Application i need It urgent, Currently i’m designing large scale GUI Using FXML that should work different Resolution.Hope this API Helps me lot.

        Thank you,

        Krunal Chaudhari
        Reply
  • 2015/12/09

    Thank You For Answer But Can You Please Give Me Any Demo Code ?

    Krunal Chaudhari
    Reply
  • 2015/12/19

    Hola, me encanto el proyecto agradezco que lo hayas compartido. Queria preguntarte si podrías compartir el codigo de las demos de los videos o realizar una demo para conocer como implementar tu proyecto ?
    Desde ya gracias, saludos!

    Flavio Rossi
    Reply
    • 2015/12/20

      Hi, can you write your comment in english please. I can’t understand it completely. Thanks.

      Reply
      • 2016/03/29

        Hi! Sorry. I wondering if you can share the code of the examples for to know how implements the proyect. Thanks!

        Flavio Rossi
        Reply
        • 2016/04/19

          Hi, yes please share the code. There is so little documentation on this!

          Sebastian
          Reply
  • 2016/01/06

    I’m getting exception n this line:
    ResponsiveHandler.addResponsiveToWindow(primaryStage);

    Code:
    @Override
    public void start(Stage primaryStage) throws Exception {
    primaryStage.setScene(scene);
    ResponsiveHandler.addResponsiveToWindow(primaryStage);
    primaryStage.show();
    }

    Exception:
    Exception in thread “JavaFX Application Thread” java.lang.RuntimeException: StackPane.managed : A bound value cannot be set.
    at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:140)
    at javafx.scene.Node.setManaged(Node.java:2389)
    at com.guigarage.responsive.ResponsiveHandler.updateManagedProperty(ResponsiveHandler.java:67)
    at com.guigarage.responsive.ResponsiveHandler.updateManagedPropertyForAllChildren(ResponsiveHandler.java:55)
    at com.guigarage.responsive.ResponsiveHandler.lambda$addResponsiveToWindow$7(ResponsiveHandler.java:40)
    at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:137)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
    at javafx.beans.property.ReadOnlyDoubleWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyDoubleWrapper.java:177)
    at javafx.beans.property.ReadOnlyDoubleWrapper.fireValueChangedEvent(ReadOnlyDoubleWrapper.java:143)
    at javafx.beans.property.DoublePropertyBase.markInvalid(DoublePropertyBase.java:113)
    at javafx.beans.property.DoublePropertyBase.set(DoublePropertyBase.java:147)
    at javafx.stage.Window.notifySizeChanged(Window.java:405)
    at javafx.stage.Window$1.notifySizeChanged(Window.java:102)
    at com.sun.javafx.stage.WindowHelper.notifySizeChanged(WindowHelper.java:56)
    at com.sun.javafx.stage.WindowPeerListener.changedSize(WindowPeerListener.java:54)
    at com.sun.javafx.tk.quantum.GlassWindowEventHandler.run(GlassWindowEventHandler.java:91)
    at com.sun.javafx.tk.quantum.GlassWindowEventHandler.run(GlassWindowEventHandler.java:40)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.quantum.GlassWindowEventHandler.lambda$handleWindowEvent$423(GlassWindowEventHandler.java:150)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
    at com.sun.javafx.tk.quantum.GlassWindowEventHandler.handleWindowEvent(GlassWindowEventHandler.java:148)
    at com.sun.glass.ui.Window.handleWindowEvent(Window.java:1266)
    at com.sun.glass.ui.Window.notifyResize(Window.java:1225)
    at com.sun.glass.ui.win.WinWindow._setBounds(Native Method)
    at com.sun.glass.ui.Window.setBounds(Window.java:572)
    at com.sun.javafx.tk.quantum.WindowStage.setBounds(WindowStage.java:318)
    at javafx.stage.Window$TKBoundsConfigurator.apply(Window.java:1274)
    at javafx.stage.Window.applyBounds(Window.java:1164)
    at javafx.stage.Window.adjustSize(Window.java:253)
    at javafx.stage.Window.access$600(Window.java:77)
    at javafx.stage.Window$9.invalidated(Window.java:851)
    at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:109)
    at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:144)
    at javafx.stage.Window.setShowing(Window.java:922)
    at javafx.stage.Window.show(Window.java:937)
    at javafx.stage.Stage.show(Stage.java:259)
    at ph.com.fsoft.hris.time.view.HrisTimeApplication.start(HrisTimeApplication.java:39)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
    at java.lang.Thread.run(Thread.java:745)

    Warren M. Nocos
    Reply
  • 2016/05/18

    Dear Mr Edders,

    First, thanks for this library.

    I have a problem using the last version, 0.8. The pseudo classes are not recognized.
    Here is the part of the code using your library:

    Oli
    Reply
    • 2016/05/18


      Stage stage = new Stage();
      stage.setTitle(“Sample”);
      Group root = new Group();
      root.getChildren().add(samplePane);
      Scene scene = new Scene(root, 1200, 400);
      stage.setScene(scene);
      ResponsiveHandler.addResponsiveToWindow(stage);
      stage.show();

      Oli
      Reply
      • 2016/05/18

        My CSS is

        .label:extreme-small-device {
        -fx-font-size: 6;
        }

        .label:small-device {
        -fx-font-size: 9;
        }

        .label:medium-device {
        -fx-font-size: 12;
        }

        .label:large-device {
        -fx-font-size: 30;
        }
        But this style is never applied to the labels of my screen.

        Oli
        Reply
        • 2016/05/18

          I can confirm that the CSS is correctly linked to the scene through the fxml as the following style (without pseudo classes) is correctly taken into account:
          .label {
          -fx-font-size: 30;
          }
          I am using the JDK 8 u77.
          Thanks a lot in advance for your help.

          Oli
          Reply
    • 2016/05/18

      Sorry, I was not looking at the right piece of code….The pseudo classes are recognized, the lib works perfectly. Sorry again.

      Oli
      Reply