Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

How to Integrate JavaFX into the NetBeans Platform Menubar

DZone's Guide to

How to Integrate JavaFX into the NetBeans Platform Menubar

· Java Zone ·
Free Resource

Build vs Buy a Data Quality Solution: Which is Best for You? Gain insights on a hybrid approach. Download white paper now!

Let's say you want to replace the NetBeans Platform menubar, written in Swing, with one written in JavaFX. Why? For fun. Also, CSS stylesheet support in JavaFX is handy for redesigning the menubar's appearance: 

The coloring in the menubar above, which is indeed a JavaFX MenuBar, is as follows:

/*Menu Bar*/
.menu-bar {
    -fx-background-color: orange;
}

/*Menus*/
.menu .label {
    -fx-text-fill: black;
}

/*Menu Items*/
.menu-item:focused {
    -fx-background-color: greenyellow;
}
.menu-item .label {
    -fx-text-fill: black;
}

Here's some references relevant to this task:

And here's the steps, all based on the links above:

  1. Remove the default menubar and replace with your own:
    package org.demo.menu;
    
    import org.openide.modules.OnStart;
    
    @OnStart
    public class Installer implements Runnable {
    
        @Override
        public void run() {
            System.setProperty("netbeans.winsys.menu_bar.path", "LookAndFeel/MenuBar.instance");
        }
    
    }
  2. In the layer, i.e., as referred to in the folder location above, define your Swing menubar:
    <folder name="LookAndFeel">
        <file name="MenuBar.instance">
            <attr name="instanceOf" stringvalue="org.openide.awt.MenuBar"/>
            <attr name="instanceCreate" newvalue="org.demo.menu.MyMenuBar"/>
        </file>
    </folder>
  3. Now create the class that you defined above. Start by putting a JFXPanel into the Swing menubar. Then you're good to go. Just add the MenuBar, Menus, and MenuItems from JavaFX, based on what you find in the relevant folders in the application's filesystem.
    public class MyMenuBar extends JMenuBar {
    
        public MyMenuBar() {
            final JFXPanel menuFxPanel = new JFXPanel();
            add(menuFxPanel);
            Platform.setImplicitExit(false);
            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    Scene scene = new Scene(new VBox(), 400, 20);
                    scene.getStylesheets().add(MyMenuBar.class.
                            getResource("myMenuBar.css").toExternalForm());
                    MenuBar menuBar = new MenuBar();
                    FileObject menuFolder = FileUtil.getConfigFile("Menu");
                    FileObject[] menuKids = menuFolder.getChildren();
                    for (FileObject menuKid : FileUtil.getOrder(Arrays.asList(menuKids), true)) {
                        Menu newMenuFromFileObject = new Menu(menuKid.getName());
                        menuBar.getMenus().add(newMenuFromFileObject);
                        builtMenuStructure(menuKid, newMenuFromFileObject);
                    }
                    ((VBox) scene.getRoot()).getChildren().addAll(menuBar);
                    menuFxPanel.setScene(scene);
                }
            });
        }
    
        private void builtMenuStructure(FileObject fo, Menu menu) {
            DataFolder df = DataFolder.findFolder(fo);
            DataObject[] childs = df.getChildren();
            for (DataObject oneChild : childs) {
                if (oneChild.getPrimaryFile().isFolder()) {
                    FileObject childFo = oneChild.getPrimaryFile();
                    Menu newMenu = new Menu(childFo.getName());
                    menu.getItems().add(newMenu);
                    builtMenuStructure(childFo, newMenu);
                } else {
                    Object instanceObj = FileUtil.getConfigObject(
                      oneChild.getPrimaryFile().getPath(), 
                      Object.class);
                    if (instanceObj instanceof JSeparator) {
                        menu.getItems().add(new SeparatorMenuItem());
                    } else if (instanceObj instanceof Action) {
                        final Action a = (Action) instanceObj;
                        String name = (String) a.getValue(Action.NAME);
                        String cutAmpersand = Actions.cutAmpersand(name);
                        MenuItem menuItem = new MenuItem(cutAmpersand);
                        menuItem.setOnAction(new EventHandler<ActionEvent>() {
                            @Override
                            public void handle(final ActionEvent t) {
                                try {
                                    SwingUtilities.invokeAndWait(new Runnable() {
                                        @Override
                                        public void run() {
                                            java.awt.event.ActionEvent event =
                                                    new java.awt.event.ActionEvent(
                                                    t.getSource(),
                                                    t.hashCode(),
                                                    t.toString());
                                            a.actionPerformed(event);
                                        }
                                    });
                                } catch (InterruptedException ex) {
                                    Exceptions.printStackTrace(ex);
                                } catch (InvocationTargetException ex) {
                                    Exceptions.printStackTrace(ex);
                                }
                            }
                        });
                        menu.getItems().add(menuItem);
                    }
                }
            }
        }
    
    }

That's all and you're done. Congratulations, you've replaced the default Swing menubar in the NetBeans Platform with a new one defined in JavaFX.

Maybe handy to know what the import statement in the above class are:

import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.layout.VBox;
import javax.swing.Action;
import javax.swing.JMenuBar;
import javax.swing.JSeparator;
import javax.swing.SwingUtilities;
import org.openide.awt.Actions;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataFolder;
import org.openide.loaders.DataObject;
import org.openide.util.Exceptions;

Build vs Buy a Data Quality Solution: Which is Best for You? Maintaining high quality data is essential for operational efficiency, meaningful analytics and good long-term customer relationships. But, when dealing with multiple sources of data, data quality becomes complex, so you need to know when you should build a custom data quality tools effort over canned solutions. Download our whitepaper for more insights into a hybrid approach.

Topics:

Opinions expressed by DZone contributors are their own.

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

{{ parent.tldr }}

{{ parent.urlSource.name }}