Undecorator – “Add a better look to your JavaFX stages” – Part I


Each time, when I start a new JavaFX project all begins with the following generated code:

public class UndecoratorStageDemo extends Application {

@Override
 public void start(final Stage stage) throws Exception {

Parent root = FXMLLoader.load(getClass().getResource("ClientArea.fxml"));

Scene scene = new Scene(root);

stage.setScene(scene);

stage.show();
 }

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

And the visual result is obviously the same as in the Scene Builder once launched from Netbeans:

Classic look under Windows 7

Classic look under Windows 7

The window style is inherited from the system. Since I’d like my application to have a consistent look (not mixing Windows frame decoration and JFX content) I immediately activated the “undecorated” flag of the stage and of course I’ve lost all resize, move, maximize… capabilities.
Currently using JavaFX, there’s no out of the box skin for undecorated window, so I started working on a humble implementation as a learning purpose.

UnDecorate this!

Since I’d like to reuse this work for many project, I wrote kind of an helper class to decorate the main stage. Here is the current usage:

Instead of:

Parent root = FXMLLoader.load(getClass().getResource("ClientArea.fxml";));

Scene scene = new Scene(root);

Simply add the Undecorator jar into your classpath and add Undecorator calls into your code, and set it as root of the scene:

        Parent root = FXMLLoader.load(getClass().getResource("ClientArea.fxml"));
        Undecorator undecorator = new Undecorator(stage, root);

       // Default theme
        undecorator.getStylesheets().add("skin/undecorator.css");

        Scene scene = new Scene(undecorator);

In order to add the nice Drop Shadow effect, adjust your Scene and Stage to be TRANSPARENT:

// Transparent scene and stage
 scene.setFill(Color.TRANSPARENT);
 stage.initStyle(StageStyle.TRANSPARENT);

The complete stage initialization looks like:

public class UndecoratorStageDemo extends Application {

@Override
 public void start(final Stage stage) throws Exception {

 Parent root = FXMLLoader.load(getClass().getResource("ClientArea.fxml"));
 Undecorator undecorator = new Undecorator(stage,root);
 undecorator.getStylesheets().add("skin/undecorator.css");
 Scene scene = new Scene(undecorator);

 // Transparent scene and stage
 scene.setFill(Color.TRANSPARENT);
 stage.initStyle(StageStyle.TRANSPARENT);

// Set minimum size
stage.setMinWidth(500);
stage.setMinHeight(400);

 stage.setTitle("No title bar");
 stage.setScene(scene);

 stage.show();
 }

And? UI make-up!

Simpyl as the undecorator.jar into your classpath and that’s it:

(Un)decoration!

(Un)decoration!

Looks better no :-) ?

Recipe

Four “layers”:

  1. A transparent Stage with Drop shadow effect
  2. Your Content
  3. A transparent decoration layer with all actions and menu.
  4.  A frame for resize capabilities,
Layers of the implementation

Layers of the implementation

The main interest in having layers is it allows to create”non rectangular” user interfaces such as the example below (GitHub Windows client mimic):

Ever seen this before ...

Ever seen this before …

Customize it! Play with skin/undecorator.css

Use your imagination !

.undecorator-background {
  -fx-fill: radial-gradient(focus-angle 45deg, focus-distance 20%, center 25% 25%, radius 50%, reflect, #eeeeee88, #55555588 75%, dimgray);
  -fx-arc-width:25;
  -fx-arc-height:25;
}

Result is:

roundedbordersAndRadialGradientTransparent

You also can  provide your own “stagedecoration.fxml” i.e. all buttons of the transparent decoration pane. As an example,  the built-in one is in  /insidefx/undecorator. Simply copy it, reuse the fx:id, and the built-in controller will handle actions on your buttons.

In you main class, invoke the constuctor with a third parameter:

    Undecorator undecorator = new Undecorator(stage, myClientArea, "mystagedecoration.fxml");

From classic to fancy look:

Code

Test it on your machine by clicking on this executable macJar

Access to the code, project and binaries here:github-logo-transparent

Next Enhancements

  • Bugs
  • API
  • Stage “Utility” style,
  • Win7 window behavior on desktop’s edges
  • i18n
  • Themes

Please share your feedbacks, bugs, request for enhancement in the comment section.

Thanks!

About these ads

  1. #1 by Lakatos Gyula on 04/02/2013 - 15:04

    Why this is not in jfxtras yet? :) Very nice work! When I’ll arrive at home I’ll try it asap. :)

    • #2 by arnaud nouard on 04/02/2013 - 18:39

      I still wonder why :-) !
      Thanks for your feedback so far…

      • #3 by Lakatos Gyula on 05/02/2013 - 22:43

        Hmm pretty impressive! What I would done differently: drop everything under JFX 2.2, because thats bundled with 7u6, so that’s what the big majority of people use. This way you can get rid of the Initializable interface, and the static controllers and load the fxml in the constructor instead (http://docs.oracle.com/javafx/2/fxml_get_started/custom_control.htm#BABDAAHE).

      • #4 by arnaud nouard on 06/02/2013 - 08:08

        Excellent idea, I didn’t notice this new shortcut of 2.2. Refactoring in progress :-)
        Thanks.

  2. #5 by Daniel Zimmermann on 05/02/2013 - 15:21

    I just read about it on fxexperience.com – I would have needed this earlier during my “JavaFX2 learning session”…
    Whatever: Great job and hopefully it will find a way into jfxtras!?

    If I find soe time, I will definitly will play a bit around with it.
    I still hope, I can convince my company to make use of JavaFX :-p

    • #6 by Lakatos Gyula on 06/02/2013 - 09:11

      I’m also had to think a lot, because it’s not fit into my application on the way I want. (I’m pretty critical.) This is just an idea but: why not extend the Scene class to create an UndecoratedScene. This would open up a lot of possibilities, like using the scene’s stage by default, or override the set/getRoot methods (if this not collapse the underlying drawing API), so the getRoot would return the nodes inside the decoration. (Not the Undecorate class itself, like now.) It would be awesome if we can manage that a ‘new UndecoratedScene(rootnode);’ would be enough to create the undecoration effect. This is just an idea, popped out from my head when I was on the way to work, maybe it works, maybe not. What do you think?

      Also it would be cool that if I set the stage’s resizable property to false, then it would disable the resizeable effect (border). It’s not supported right now.

      Also sorry for my pretty bad english, I rarery write such a long posts. :)

      • #7 by Lakatos Gyula on 06/02/2013 - 09:12

        Ohh I replied to the wrong post, sorry! :S

  3. #8 by http://yahoo.com on 09/02/2013 - 15:04

  4. #9 by devov on 14/02/2013 - 10:58

    Pretty cool, almost exactly what I was looking for.

    A few issues on multimonitor systems:
    -Maximize will always maximize it to the primary screen, rather than the current screen.
    -Moving the window between two screens is inconsistent. It drops the mouse drag event at the screen edges (unless you move the mouse fast enough that you don’t trigger a mouse event right on the screen edge).

  5. #11 by devov on 22/02/2013 - 02:07

    I set up something similar using regions in the scene builder.

    https://nooleanbot.wordpress.com/

    • #12 by arnaud nouard on 22/02/2013 - 20:15

      Nice approach Devov and thanks for the reference in your blog.

  6. #13 by NooleanBot on 25/02/2013 - 02:27

    I was trying to set some custom closing code to execute for different stages using:

    stage.setOnCloseRequest(new EventHandler() {
    @Override
    public void handle(WindowEvent evt) {
    System.out.println(“testing the close operation”);
    }
    });

    In order to fire that event you have to use:

    stage.fireEvent(new WindowEvent(stage, WindowEvent.WINDOW_CLOSE_REQUEST));

    rather than stage.close() or stage.hide() for window closing.

    Not sure if that is the real close operation you’re looking for, or if there is a better way to do it.

    It is nice to be able to do when you want to prompt the user to save, or disconnect from resources, or store the window size and location preferences.

    Thanks for all the updates.

    • #14 by arnaud nouard on 25/02/2013 - 07:18

      Excellent. The window listeners was on my TODO list. I’ll try to test and add this ASAP, as well as the fullscreen and stage icons.
      Thanks!

  7. #15 by Aksel on 08/04/2013 - 09:39

    Hi, very nice exmaple. May i ask if undecorator.jar is available in some maven repo or maybe as binary?

    • #16 by arnaud nouard on 08/04/2013 - 17:48

      Hi,
      Thanks for the feedback. You can take a look at the code and the executable jar by clicking on the image links you will find in he post (GitHub).
      Thanks

  8. #17 by munesh meena on 06/05/2013 - 11:39

    its nice and helpful ..

  9. #18 by Damin on 27/06/2013 - 15:10

    Hello
    I have to say that your idea is amazing! I was wondering if your code is completely open source and if I can use it in a commercial application?
    Thanks for a reply!

    • #19 by arnaud nouard on 27/06/2013 - 15:26

      Hi Damin,
      Thanks a lot for your feedback.
      Feel free to use it for any kind of application, commercial or not, and keep me informed if you can :).
      Thanks.

  10. #20 by douglasparedes on 04/07/2013 - 01:04

    I wanna know how to add many scene. I mean , with a button I want to go to another scene and so

    • #21 by arnaud nouard on 04/07/2013 - 23:33

      Hi,
      The problem is that the Scene and the Stage are linked in the Undecorator scenario (i.e. 1:1). The scene becomes a window with decorations and the Stage becomes transparent.
      So, for your needs you probably have to customize the Undecorator class to support multiple Scene by keeping the decoration layer the same for all different Scenes.
      Hope this helps
      Thanks.

  11. #22 by douglasparedes on 06/07/2013 - 02:29

    wow that could be hard to me hehe , could you make a version to do that?

    • #23 by arnaud nouard on 11/07/2013 - 10:00

      If you directly use the Undecorator class, not the UndecoratorScene, you should be able to do what you need.
      Example:

      public class UndecoratorStageDemo extends Application {
       
      @Override
       public void start(final Stage stage) throws Exception {
       
       Parent root = FXMLLoader.load(getClass().getResource("ClientArea.fxml"));
       Undecorator undecorator = new Undecorator(stage,root);
       undecorator.getStylesheets().add("skin/undecorator.css");
       Scene scene = new Scene(undecorator);
       
       // Transparent scene and stage
       scene.setFill(Color.TRANSPARENT);
       stage.initStyle(StageStyle.TRANSPARENT);
       
      // Set minimum size
      stage.setMinWidth(500);
      stage.setMinHeight(400);
       
       stage.setTitle("No title bar");
       stage.setScene(scene);
       
       stage.show();
       }

      In that scenario the Scene is no longer managed by the Undecorator, so you can switch between your different Scene.
      BTW, I still don’t understand why you change your Scene using a Button instead of changing the Root node of the Scene.
      Thanks.

  12. #24 by Joern on 15/07/2013 - 11:46

    Hi Arnaud!

    First of all, thank you a lot for 4-Layer recipe. I was working on my own on a similar solution. And I think, you can remove the shadow layer completely, by using padding (insets) for the “root”-node of the client-layer. This will create a space (padding) between the stage and the scene. To now drop a shadow, simply use CSS for the root-node.

    For example:
    .root {
    -fx-border-style: none;
    -fx-effect: dropshadow(gaussian,rgba(0,0,0,0.5), 30, 0, 0, 15);
    }

    With this approach, your awesome framework could maybe become even more simpler I hope.

    Best regards,
    Jörn

    • #25 by arnaud nouard on 17/07/2013 - 23:02

      Thanks a lot Joern for your feedback and advice.
      As far as I remember, I’ve seen this technique in the Ensemble demo set.
      But for managing the shadow for focused, maximized and fullscreen mode I don’t see how to handle that from a css value compared to programmatic approach.
      If you have further details, I’m still interesting :).
      Thanks so far!

  13. #26 by Mario on 19/01/2014 - 16:20

    Hey insideFX. I’m a great fan of your Undecorator. I made a plugin for resizing stages comfortably and just had the idea to make a fourth button next to minize which could popup my ScreenFX arranger. just look here: http://vmario89.github.io/ScreenFX/. Greetings, Mario

  1. Java desktop links of the week, February 4 | Jonathan Giles
  2. JavaFX links of the week, February 4 // JavaFX News, Demos and Insight // FX Experience

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 57 other followers

%d bloggers like this: