JFXtras RadialMenu for NetBeans RCP (Part 2)

DZone 's Guide to

JFXtras RadialMenu for NetBeans RCP (Part 2)

· Java Zone ·
Free Resource

This article is Part 2 of a tutorial that will walk through adapting an open source JavaFX RadialMenu ( http://jfxtras.org/ ) to replace the NetBeans Platform system menu.  It will build upon both previous tutorials and Part 1  that demonstrate complete replacements for the default NetBeans Swing components using JavaFX.  Code examples will feature NetBeans Platform, JavaFX and CSS. 

Part 1  of the article walks through some of the code upgrades necessary for the task.  As of this article’s writing the open-source JFXtras RadialMenu needed a few upgrades to act as a system menu replacement for a NetBeans Platform RCP.  Part 2 will show the specific algorithm and code to then utilize the upgraded RadialMenu as described.  When complete you should be able to produce a slick radial system menu like this:

Previous tutorials in the Integrating JavaFX with the NetBeans Platform series we showed how to replace the NetBeans Swing MenuBar with JavaFX components.  You can find these tutorials here (first link is Part 1):




And they are extensions themselves of these great articles written by Geertjan Wielenga:



To fully understand and follow this tutorial you will need to start with the previous tutorials mentioned above, especially Part 1.

Create Recursive Container Building Method

Like most of the previous Menu replacement articles, we are going to use  recursion to build our components.  In this situation we want to recursively build our extended RadialContainerMenuItemSP components that we upgraded in Part 1 of this tutorial.  Add this recursive method to your JFXRadial component class:

private void buildRadialContainerMenuItem(FileObject fo, final RadialContainerMenuItemSP rcmi) {
  DataFolder df = DataFolder.findFolder(fo);
  DataObject[] childs = df.getChildren();
  for (DataObject oneChild : childs) {
  //Create filler graphic for container 
  ImageView filler = ImageViewBuilder
  .image(new Image("jfxradial/dark_compass_icon_16.png")).build();
  if(fo.getName().equals("Web Browser")) {
  //If child is folder we need to build recursively
  if (oneChild.getPrimaryFile().isFolder()) {
  FileObject childFo = oneChild.getPrimaryFile();
  //Create RadialMenuContainerItemSP
  final RadialContainerMenuItemSP newContainerItem = new RadialContainerMenuItemSP(containerSize, childFo.getName(), filler, false);
  //Recursively build submenu
  buildRadialContainerMenuItem(childFo, newContainerItem);
  //add RadialMenuContainerItem to RadialMenu
  else {
  Object instanceObj = FileUtil.getConfigObject(oneChild.getPrimaryFile().getPath(), Object.class);
  if (instanceObj instanceof Action) {
  //If it is an Action we have reached an endpoint
  final Action a = (Action) instanceObj;
  String name = (String) a.getValue(Action.NAME);
  String cutAmpersand = Actions.cutAmpersand(name);
  //Create RadialMenuItemSP
  final MenuEventHandler meh = new MenuEventHandler(a);
  //add action to RadialMenuItemSP and hide graphic filler
  final RadialMenuItemSP menuItem = new RadialMenuItemSP(menuSize, cutAmpersand, filler, false, meh);
  //add RadialMenuItemSP to RadialContainerMenuItem

The recursion process of course looks very similar to that found in our previous articles.  One thing to note here that the way that because the RadialContainerMenuItem class extends the RadialMenuItem class and because of the logic we added to dynamically provide MouseClicked event handling, we can recursively build a RadialContainerMenuItemSP with as many nested levels as the JDK has memory.  Then only the root node in the chain needs to be added to the RadialMenu itself.

Feed the NetBeans Platform system folders into the recursion

Add this block of code to the end of your createRadialMenu() method:

  FileObject menuFolder = FileUtil.getConfigFile("Menu");
  FileObject[] menuKids = menuFolder.getChildren();
  //for each Menu folder need to create either RadialMenuItemSP or a RadialMenuContainerItem to hold sub menus
  for (FileObject menuKid : FileUtil.getOrder(Arrays.asList(menuKids), true)) {
  try {
  //Create filler graphic for container 
  ImageView filler = ImageViewBuilder
  .image(new Image("jfxradial/dark_compass_icon_16.png")).build(); 
  //Create RadialMenuContainerItem and recurse
  //Extend a custom Container that uses text labels like we did for RadialMenuItemSP
  RadialContainerMenuItemSP newContainerItem = new RadialContainerMenuItemSP(containerSize, menuKid.getName(), filler, false); 
  buildRadialContainerMenuItem(menuKid, newContainerItem);
  //add RadialMenuContainerItem to RadialMenu
  } catch (Exception ex) {
  //we couldn’t load so drop it on the floor

Again it looks very similar to all our previous examples.  One small note here, I don’t want to actually show any graphics in my menus, only menu text labels.  So the filler ImageView object is just that… an invisible filler to satisfy the available constructors.

Adding this code should provide you with a view similar to this:

This view of course is after I’ve started clicking around expanding layers.  Wow.  That’s a lot of options.  It makes you appreciate how efficient a traditional menu is in terms of space.  So right here we’ve already encountered a problem that plagues Radial Menu’s in general… they take up a ton of space and block out whats behind them.  But JavaFX to the rescue… lets reduce the Opacity of the menu to a really low number like 0.1.  You can do this by changing the fourth component of the “slightlyTrans" Color object defined at the top of the createRadialMenu() method and recompile.  Let’s try it with something in the background like a JavaFX Web Browsing component:

Hmmm… a lot of those menu items are TOO transparent and they don’t show well over dark patterns and backgrounds.  Let’s up the opacity to 0.3…

So we’re getting closer… not bad at all on a light background and a bit better on Dark/Mixed backgrounds.  We should probably increase the opacity a bit more to 0.6.

Let’s try it on a deeply dark background like a WorldWind application!

Ugh.  That grey box represents the specified scene size inside the transparent JFXPanel component.  This is a bug when trying to overlay transparent JavaFX scenery on Native/HeavyWeight components.  Basically the Z-ordering gets mucked up.  The non-transparent nodes in the JavaFX scene are rendered properly but everything else not so much.  If someone out there has a workaround please let me and everyone else know.

So from now on we will all agree to keep our heavyweight and translucent javafx separate and our Opacity around half for all to see.  If you follow those rules and these articles you should be able to make lot’s of cool looking menus and interfaces like the one at the start of this article and the one below:


Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}