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:
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:
Looks better no
?
Recipe
Four “layers”:
- A transparent Stage with Drop shadow effect
- Your Content
- A transparent decoration layer with all actions and menu.
- A frame for resize capabilities,
The main interest in having layers is it allows to create”non rectangular” user interfaces such as the example below (GitHub Windows client mimic):
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:
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 ![]()
Access to the code, project and binaries here:
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!





#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.
#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
#8 by http://yahoo.com on 09/02/2013 - 15:04
#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).
#10 by arnaud nouard on 14/02/2013 - 23:11
Thanks Devov, will fix this ASAP…
#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.
#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!
#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
#17 by munesh meena on 06/05/2013 - 11:39
its nice and helpful ..