{"id":880,"date":"2016-06-10T14:31:07","date_gmt":"2016-06-10T12:31:07","guid":{"rendered":"http:\/\/www.pellissier.co.za\/hermien\/?p=880"},"modified":"2016-06-16T17:35:58","modified_gmt":"2016-06-16T15:35:58","slug":"javafx-makeover-for-the-netbeans-platform","status":"publish","type":"post","link":"https:\/\/www.pellissier.co.za\/hermien\/?p=880","title":{"rendered":"JavaFX makeover for the NetBeans Platform"},"content":{"rendered":"<p>I was honoured to present last weekend at the <a href=\"http:\/\/www.meetup.com\/Jozi-JUG\/events\/229688441\/?rv=ea1\" target=\"_blank\">Java 9 and Women in Tech Unconference<\/a> in Sandton, South Africa. The topic of the presentation was a JavaFX makeover for the NetBeans Platform &#8211; get the slides <a href=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/JavaFX-makeover-for-the-NetBeans-Platform.pdf\" target=\"_blank\">here<\/a>.<\/p>\n<p>Today I want to share the details of the process of transforming the GUI of an existing NetBeans Platform Application from Swing to JavaFX. There was not enough time to discuss all the details during the presentation, so I prepared the project before I started. However, here I will describe all of the steps that are required.\u00a0I am using\u00a0<a href=\"http:\/\/www.oracle.com\/technetwork\/java\/javase\/downloads\/jdk8-downloads-2133151.html\" target=\"_blank\">JDK 8<\/a>, <a href=\"https:\/\/netbeans.org\/downloads\/\" target=\"_blank\">NetBeans 8.1<\/a>\u00a0(the Java SE bundle has everything we need) and <a href=\"http:\/\/www.oracle.com\/technetwork\/java\/javase\/downloads\/javafxscenebuilder-info-2157684.html\" target=\"_blank\">Scene Builder 2.0<\/a>.<\/p>\n<p><strong>1 &#8211; Create the sample application<\/strong><\/p>\n<p>The application that I will be giving a makeover is the\u00a0Sample CRUD Application that ships with the NetBeans IDE. From the File menu, choose New Project&#8230; Browse to the Samples &gt; NetBeans modules category and choose\u00a0Sample CRUD Application. On the next page of the wizard, specify a location and click Finish.<\/p>\n<figure id=\"attachment_842\" aria-describedby=\"caption-attachment-842\" style=\"width: 727px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud01.png\"><img loading=\"lazy\" class=\"size-full wp-image-842\" alt=\"Creating the Sample CRUD Application\" src=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud01.png\" width=\"737\" height=\"508\" srcset=\"https:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud01.png 737w, https:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud01-300x206.png 300w\" sizes=\"(max-width: 737px) 100vw, 737px\" \/><\/a><figcaption id=\"caption-attachment-842\" class=\"wp-caption-text\">Creating the Sample CRUD Application<\/figcaption><\/figure>\n<p>At this point, the sample application will not compile &#8211; please read my earlier post about <a title=\"Module Dependencies and Java 8\" href=\"http:\/\/www.pellissier.co.za\/hermien\/?p=841\" target=\"_blank\">Module Dependencies and Java 8<\/a>\u00a0for more information. Here is a brief summary of the two steps that are required:<\/p>\n<ul>\n<li>Add a dependency on the Explorer &amp; Property Sheet API for the CustomerEditor module.<\/li>\n<li>Remove the\u00a0Command-line Serviceability module from the application.<\/li>\n<\/ul>\n<p>Run the application. It should look something like this:<\/p>\n<figure id=\"attachment_856\" aria-describedby=\"caption-attachment-856\" style=\"width: 700px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud03.png\"><img loading=\"lazy\" class=\"size-full wp-image-856\" alt=\"CRUD Application\" src=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud03.png\" width=\"710\" height=\"468\" srcset=\"https:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud03.png 710w, https:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud03-300x197.png 300w\" sizes=\"(max-width: 710px) 100vw, 710px\" \/><\/a><figcaption id=\"caption-attachment-856\" class=\"wp-caption-text\">Running CRUD Application<\/figcaption><\/figure>\n<p><strong>2 &#8211; Create a new module<\/strong><\/p>\n<p>Lets create a new module to house our JavaFX code. Right-click on the Modules node under the CRUD Customber DB Manager project, and choose Add New&#8230; Follow the steps of the wizard &#8211; I called my project\u00a0JavaFXWindowSystem and I chose\u00a0za.co.pellissier.javafxwindowsystem as my code name base. If you are following step by step, I suggest that you keep at least the code name base the same.<\/p>\n<figure id=\"attachment_892\" aria-describedby=\"caption-attachment-892\" style=\"width: 247px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud05.png\"><img loading=\"lazy\" class=\"size-full wp-image-892\" alt=\"Creating a new module\" src=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud05.png\" width=\"257\" height=\"109\" \/><\/a><figcaption id=\"caption-attachment-892\" class=\"wp-caption-text\">Creating a new module<\/figcaption><\/figure>\n<p><strong>3 &#8211; Find the right class to replace<\/strong><\/p>\n<p>It is possible to replace the Window System of the NetBeans Platform because it was designed right from the start in a very modular way. (Reading the platform source code, you might spot cases where there are specialized mock classes in the unit tests that are loaded just like the normal implementations, except during test execution.)<\/p>\n<p>Before continuing, you will have to download and configure the source code of the NetBeans platform if you want to follow the steps. On the NetBeans download page, you will find a link referring to ZIP files for that build. (For the latest version, that link points <a href=\"https:\/\/netbeans.org\/downloads\/zip.html\" target=\"_blank\">here<\/a>.) Download the file ending in\u00a0platform-src.zip, and extract its contents. In the NetBeans IDE, access Tools &gt; NetBeans Platforms. Under the Sources tab, choose the folder where the extracted source code lives, and close the dialog box.<\/p>\n<p>If you have worked with the NetBeans Window System before, you will probably have encountered the class WindowManager before. This is the most important class when it comes to, well, managing windows. So lets find a spot where we can debug into that class to see what is going on. The easiest spot to put the code is in module CustomerViewer,\u00a0org.netbeans.modules.customerviewer.CustomerTopComponent, in the method\u00a0componentOpened(). The framework will call this method when the window is opened. Put these two lines of code into that method:<\/p>\n<p>[java]WindowManager winMngr = WindowManager.getDefault();<br \/>\nwinMngr.getMainWindow();[\/java]<\/p>\n<p>Remember to fix any imports that are missing (Ctrl + Shift + I on Windows).<\/p>\n<p>With the platform source code set up, you can Ctrl + Left Click on the name of the WindowManager class to access the source code of the platform. Go ahead and do so &#8211; be brave! \ud83d\ude42<\/p>\n<p>[java]public abstract class WindowManager extends Object implements Serializable {[\/java]<\/p>\n<p>You will notice that WindowManager is in fact an abstract class. So we will need to locate the concrete implementation that needs replacing. The easiest way to do this in a very modular system like this is to debug. So put a breakpoint on the first line that we inserted (by clicking in the left margin) and start the application in debug mode by clicking the Debug Project button on the main toolbar.<\/p>\n<p>When the breakpoint is hit, step over the first line (F8). And then step into the getMainWindow() call on the second line (F7). Take a look at the class that you encounter&#8230;<\/p>\n<p>[java]package org.netbeans.core.windows;<\/p>\n<p>&#8230;<\/p>\n<p>@org.openide.util.lookup.ServiceProvider(service=org.openide.windows.WindowManager.class)<br \/>\npublic final class WindowManagerImpl extends WindowManager implements Workspace {[\/java]<\/p>\n<p>We have found it &#8211; WindowManagerImpl is the class that we need to replace.<\/p>\n<p><strong>4 &#8211; Create a basic new WindowManager implementation<\/strong><\/p>\n<p>In the new za.co.pellissier.javafxwindowsystem package of the new module, create a class called JavaFXWindowManager and add the service provider annotation:<\/p>\n<p>[java]@org.openide.util.lookup.ServiceProvider(service=org.openide.windows.WindowManager.class,<br \/>\nsupersedes = &#8220;org.netbeans.core.windows.WindowManagerImpl&#8221;)<br \/>\npublic class JavaFXWindowManager extends WindowManager {[\/java]<\/p>\n<p>The annotation indicates what type of service the class provides, and it also (very important!) indicates that this new implementation will supersede the existing one.<\/p>\n<p>Now we need to add some dependencies in order to resolve all the imports.<\/p>\n<figure id=\"attachment_916\" aria-describedby=\"caption-attachment-916\" style=\"width: 284px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud09.png\"><img loading=\"lazy\" class=\"size-full wp-image-916\" alt=\"Adding a dependency\" src=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud09.png\" width=\"294\" height=\"140\" \/><\/a><figcaption id=\"caption-attachment-916\" class=\"wp-caption-text\">Adding a dependency<\/figcaption><\/figure>\n<figure id=\"attachment_917\" aria-describedby=\"caption-attachment-917\" style=\"width: 506px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud10.png\"><img loading=\"lazy\" class=\"size-full wp-image-917\" alt=\"Adding Window System API\" src=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud10.png\" width=\"516\" height=\"538\" srcset=\"https:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud10.png 516w, https:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud10-287x300.png 287w, https:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud10-24x24.png 24w\" sizes=\"(max-width: 516px) 100vw, 516px\" \/><\/a><figcaption id=\"caption-attachment-917\" class=\"wp-caption-text\">Adding Window System API dependency<\/figcaption><\/figure>\n<p>Add the following dependencies:<\/p>\n<ul>\n<li>Lookup API<\/li>\n<li>Nodes API<\/li>\n<li>Utilities API<\/li>\n<li>Window System API<\/li>\n<\/ul>\n<p>Implement all abstract methods (hint in the margin) and fix imports again if necessary.<\/p>\n<p>Quite a long list of methods will be generated, but thankfully there is only one that we are interested in implementing right now &#8211; getMainWindow(). So lets add the basics of creating a window:<\/p>\n<p>[java]@ServiceProvider(service = WindowManager.class,<br \/>\n                  supersedes = &#8220;org.netbeans.core.windows.WindowManagerImpl&#8221;)<br \/>\npublic class JavaFXWindowManager extends WindowManager {<\/p>\n<p>    public static JFrame mMainWindow = new JFrame();<\/p>\n<p>    public JavaFXWindowManager() {<\/p>\n<p>        mMainWindow.setSize(new Dimension(640, 480));<br \/>\n        mMainWindow.addWindowListener(new WindowAdapter()<br \/>\n        {<br \/>\n            @Override<br \/>\n            public void windowClosing(WindowEvent evt)<br \/>\n            {<br \/>\n               LifecycleManager.getDefault().exit();<br \/>\n            }<br \/>\n        }<br \/>\n        );<br \/>\n    }<\/p>\n<p>    @Override<br \/>\n    public Frame getMainWindow() {<br \/>\n        return mMainWindow;<br \/>\n    }[\/java]<\/p>\n<p>When you fix imports, make sure that you import java.awt.event.WindowEvent and NOT the JavaFX equivalent!<\/p>\n<p>Note that I added a call to the NetBeans Platform&#8217;s LifecycleManager when the application is closed. This ensures that the normal process will be followed for shutting the application down, just like the original Window System would have done.<\/p>\n<p><strong>5 &#8211; Fix the issues caused by replacing the WindowManager<\/strong><\/p>\n<p>Clean and build, and then run the application, and have a look at the exception that is raised by the framework:<\/p>\n<p>[text]java.lang.ClassCastException: za.co.pellissier.javafxwindowsystem.JavaFXWindowManager cannot be cast to org.netbeans.core.windows.WindowManagerImpl<br \/>\n    at org.netbeans.core.windows.WindowManagerImpl.getInstance(WindowManagerImpl.java:148)<br \/>\n    at org.netbeans.core.windows.WindowSystemImpl.load(WindowSystemImpl.java:78)<br \/>\n    at org.netbeans.core.GuiRunLevel$InitWinSys.run(GuiRunLevel.java:229)<br \/>\n    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)<br \/>\n    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)<br \/>\n&#8230;<br \/>\n[\/text]<\/p>\n<p>So we see that there is another class that is involved &#8211; WindowSystemImpl. Let us replace it with a new class as well &#8211; create a class called JavaFXWindowSystem in the same package:<\/p>\n<p>[java]@ServiceProvider(service=WindowSystem.class, supersedes = &#8220;org.netbeans.core.windows.WindowSystemImpl&#8221;)<br \/>\npublic class JavaFXWindowSystem implements WindowSystem {<\/p>\n<p>    @Override<br \/>\n    public void init() {<br \/>\n    }<\/p>\n<p>    @Override<br \/>\n    public void show() {<br \/>\n        JavaFXWindowManager.getDefault().getMainWindow().setVisible(true);<br \/>\n    }<\/p>\n<p>    @Override<br \/>\n    public void hide() {<br \/>\n        JavaFXWindowManager.getDefault().getMainWindow().setVisible(false);<br \/>\n    }<\/p>\n<p>    @Override<br \/>\n    public void load() {<br \/>\n    }<\/p>\n<p>    @Override<br \/>\n    public void save() {<br \/>\n    }<br \/>\n}[\/java]<\/p>\n<p>This time adding the required dependencies is more difficult. We need a dependency on the Core module &#8211; click the Show Non-API Module checkbox to even see it on the list of dependencies.<\/p>\n<figure id=\"attachment_930\" aria-describedby=\"caption-attachment-930\" style=\"width: 506px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud11.png\"><img loading=\"lazy\" src=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud11.png\" alt=\"Add a dependency on Core\" width=\"516\" height=\"538\" class=\"size-full wp-image-930\" srcset=\"https:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud11.png 516w, https:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud11-287x300.png 287w, https:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud11-24x24.png 24w\" sizes=\"(max-width: 516px) 100vw, 516px\" \/><\/a><figcaption id=\"caption-attachment-930\" class=\"wp-caption-text\">Add a dependency on Core<\/figcaption><\/figure>\n<p>Once it is added, edit the dependency and set it to use implementation version.<\/p>\n<figure id=\"attachment_933\" aria-describedby=\"caption-attachment-933\" style=\"width: 223px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud12.png\"><img loading=\"lazy\" src=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud12.png\" alt=\"Editing dependency\" width=\"233\" height=\"196\" class=\"size-full wp-image-933\" \/><\/a><figcaption id=\"caption-attachment-933\" class=\"wp-caption-text\">Editing dependency<\/figcaption><\/figure>\n<figure id=\"attachment_932\" aria-describedby=\"caption-attachment-932\" style=\"width: 406px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud13.png\"><img loading=\"lazy\" src=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud13.png\" alt=\"Setting implementation version\" width=\"416\" height=\"388\" class=\"size-full wp-image-932\" srcset=\"https:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud13.png 416w, https:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud13-300x279.png 300w\" sizes=\"(max-width: 416px) 100vw, 416px\" \/><\/a><figcaption id=\"caption-attachment-932\" class=\"wp-caption-text\">Setting implementation version<\/figcaption><\/figure>\n<p>If you do not do this, you will see this error message:<\/p>\n<p>[text]The module za.co.pellissier.javafxwindowsystem is not a friend of org-netbeans-core.jar[\/text]<\/p>\n<p>Do take note that this means that you are setting a dependency on a very specific version of the Core module &#8211; should you ever change the version of the NetBeans Platform that you build against, you would have to fix this dependency!<\/p>\n<p>You will have to stop the previous execution from the IDE before running the application again. Running it again now shows a very minimal JFrame:<\/p>\n<figure id=\"attachment_906\" aria-describedby=\"caption-attachment-906\" style=\"width: 630px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud06.png\"><img loading=\"lazy\" class=\"size-full wp-image-906\" alt=\"Empty JFrame\" src=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud06.png\" width=\"640\" height=\"480\" srcset=\"https:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud06.png 640w, https:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud06-300x225.png 300w\" sizes=\"(max-width: 640px) 100vw, 640px\" \/><\/a><figcaption id=\"caption-attachment-906\" class=\"wp-caption-text\">Empty JFrame<\/figcaption><\/figure>\n<p><strong>6 &#8211; Including Branding<\/strong><\/p>\n<p>A NetBeans Platform Application includes branding information &#8211; application icons, splash screen image and so forth. To improve the look of our very basic JFrame, we can use some of these elements:<\/p>\n<p>[java]public JavaFXWindowManager() {<\/p>\n<p>    mMainWindow.setSize(new Dimension(640, 480));<br \/>\n    mMainWindow.addWindowListener(new WindowAdapter()<br \/>\n    {<br \/>\n        @Override<br \/>\n        public void windowClosing(WindowEvent evt)<br \/>\n        {<br \/>\n            LifecycleManager.getDefault().exit();<br \/>\n        }<br \/>\n    }<br \/>\n    );<\/p>\n<p>    String title = NbBundle.getBundle(&#8220;org.netbeans.core.windows.view.ui.Bundle&#8221;).getString(&#8220;CTL_MainWindow_Title_No_Project&#8221;); \/\/NOI18N<br \/>\n    if (!title.isEmpty())<br \/>\n    {<br \/>\n        mMainWindow.setTitle(title);<br \/>\n    }<br \/>\n    mMainWindow.setIconImages(Arrays.asList(<br \/>\n        ImageUtilities.loadImage(&#8220;org\/netbeans\/core\/startup\/frame.gif&#8221;, true),<br \/>\n        ImageUtilities.loadImage(&#8220;org\/netbeans\/core\/startup\/frame32.gif&#8221;, true),<br \/>\n        ImageUtilities.loadImage(&#8220;org\/netbeans\/core\/startup\/frame48.gif&#8221;, true)));<br \/>\n    mMainWindow.setLayout(new java.awt.BorderLayout());<br \/>\n}[\/java]<\/p>\n<p>Add a dependency on the Base Utilities API module and fix imports.<\/p>\n<p>Now the main window title and application icons are set just like would be done for a standard NetBeans Platform application. So you can configure these elements in the normal branding window in the IDE!<\/p>\n<figure id=\"attachment_910\" aria-describedby=\"caption-attachment-910\" style=\"width: 630px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud07.png\"><img loading=\"lazy\" class=\"size-full wp-image-910\" alt=\"With Branding\" src=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud07.png\" width=\"640\" height=\"480\" srcset=\"https:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud07.png 640w, https:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud07-300x225.png 300w\" sizes=\"(max-width: 640px) 100vw, 640px\" \/><\/a><figcaption id=\"caption-attachment-910\" class=\"wp-caption-text\">With Branding<\/figcaption><\/figure>\n<p><strong>7 &#8211; Building a new GUI<\/strong><\/p>\n<p>All the difficult parts are now done &#8211; from this point on, we can develop a normal JavaFX GUI using SceneBuilder and the JavaFX infrastructure in the NetBeans IDE. Here is the contents of my crudwindow.fxml file:<\/p>\n<p>[xml]<?xml version=\"1.0\" encoding=\"UTF-8\"?><\/p>\n<p><?import javafx.scene.control.*?><br \/>\n<?import java.lang.*?><br \/>\n<?import javafx.scene.layout.*?><\/p>\n<p><AnchorPane maxHeight=\"-Infinity\" maxWidth=\"-Infinity\" minHeight=\"-Infinity\" minWidth=\"-Infinity\" prefHeight=\"276.0\" prefWidth=\"600.0\" xmlns=\"http:\/\/javafx.com\/javafx\/8\" xmlns:fx=\"http:\/\/javafx.com\/fxml\/1\" fx:controller=\"za.co.pellissier.javafxwindowsystem.CrudwindowController\"><br \/>\n   <children><br \/>\n      <ListView fx:id=\"list\" prefHeight=\"400.0\" prefWidth=\"200.0\" AnchorPane.bottomAnchor=\"0.0\" AnchorPane.leftAnchor=\"0.0\" AnchorPane.topAnchor=\"0.0\" \/><br \/>\n      <Label layoutX=\"220.0\" layoutY=\"18.0\" text=\"Name:\" \/><br \/>\n      <Label layoutX=\"220.0\" layoutY=\"52.0\" text=\"City:\" \/><br \/>\n      <TextField fx:id=\"txtName\" layoutX=\"269.0\" layoutY=\"14.0\" prefHeight=\"25.0\" prefWidth=\"233.0\" \/><br \/>\n      <TextField fx:id=\"txtCity\" layoutX=\"269.0\" layoutY=\"48.0\" prefHeight=\"25.0\" prefWidth=\"233.0\" \/><br \/>\n   <\/children><br \/>\n<\/AnchorPane>[\/xml]<\/p>\n<p>And the CrudwindowController controller class, which contains bits and pieces copied from the sample code to make the DB access work:<\/p>\n<p>[java]package za.co.pellissier.javafxwindowsystem;<\/p>\n<p>import demo.Customer;<br \/>\nimport java.net.URL;<br \/>\nimport java.util.ArrayList;<br \/>\nimport java.util.List;<br \/>\nimport java.util.ResourceBundle;<br \/>\nimport javafx.beans.value.ChangeListener;<br \/>\nimport javafx.beans.value.ObservableValue;<br \/>\nimport javafx.collections.FXCollections;<br \/>\nimport javafx.collections.ObservableList;<br \/>\nimport javafx.fxml.FXML;<br \/>\nimport javafx.fxml.Initializable;<br \/>\nimport javafx.scene.control.ListView;<br \/>\nimport javafx.scene.control.TextField;<br \/>\nimport javax.persistence.EntityManager;<br \/>\nimport javax.persistence.EntityManagerFactory;<br \/>\nimport javax.persistence.Persistence;<br \/>\nimport javax.persistence.Query;<br \/>\nimport javax.swing.SwingUtilities;<br \/>\nimport org.netbeans.modules.customerdb.JavaDBSupport;<\/p>\n<p>\/**<br \/>\n * FXML Controller class<br \/>\n *<br \/>\n * @author Hermien Pellissier<br \/>\n *\/<br \/>\npublic class CrudwindowController implements Initializable {<\/p>\n<p>    @FXML<br \/>\n    private ListView<CustomerWrapper> list;<br \/>\n    @FXML<br \/>\n    private TextField txtName;<br \/>\n    @FXML<br \/>\n    private TextField txtCity;<\/p>\n<p>    private static class CustomerWrapper<br \/>\n    {<br \/>\n        private String displayName;<br \/>\n        private Customer customer;<\/p>\n<p>        public String getDisplayName() {<br \/>\n            return displayName;<br \/>\n        }<\/p>\n<p>        public void setDisplayName(String displayName) {<br \/>\n            this.displayName = displayName;<br \/>\n        }<\/p>\n<p>        public Customer getCustomer() {<br \/>\n            return customer;<br \/>\n        }<\/p>\n<p>        public void setCustomer(Customer customer) {<br \/>\n            this.customer = customer;<br \/>\n        }<\/p>\n<p>        @Override<br \/>\n        public String toString() {<br \/>\n            return displayName;<br \/>\n        }<br \/>\n    }<\/p>\n<p>    \/**<br \/>\n     * Initializes the controller class.<br \/>\n     *\/<br \/>\n    @Override<br \/>\n    public void initialize(URL url, ResourceBundle rb) {<br \/>\n        JavaDBSupport.ensureStartedDB();<br \/>\n        EntityManagerFactory factory = Persistence.createEntityManagerFactory(&#8220;CustomerDBAccessPU&#8221;);<br \/>\n        if (factory == null) {<br \/>\n            \/\/ XXX: message box?<br \/>\n            return ;<br \/>\n        }<br \/>\n        EntityManager entityManager = null;<br \/>\n        try {<br \/>\n            entityManager = factory.createEntityManager();<br \/>\n        } catch (RuntimeException re) {<br \/>\n            \/\/ XXX: message box?<br \/>\n            return ;<br \/>\n        }<br \/>\n        final Query query = entityManager.createQuery(&#8220;SELECT c FROM Customer c&#8221;);<br \/>\n        SwingUtilities.invokeLater(new Runnable () {<br \/>\n            @Override<br \/>\n            public void run() {<br \/>\n                @SuppressWarnings(&#8220;unchecked&#8221;)<br \/>\n                List<Customer> resultList = query.getResultList();<br \/>\n                List<CustomerWrapper> wrappersList = new ArrayList<>();<br \/>\n                for (Customer customer : resultList) {<br \/>\n                    CustomerWrapper w = new CustomerWrapper();<br \/>\n                    w.setCustomer(customer);<br \/>\n                    w.setDisplayName(customer.getName());<br \/>\n                    wrappersList.add(w);<br \/>\n                }<br \/>\n                ObservableList<CustomerWrapper> items = FXCollections.observableArrayList(wrappersList);<br \/>\n                list.setItems(items);<br \/>\n            }<br \/>\n        });<\/p>\n<p>        list.getSelectionModel().selectedItemProperty().addListener(<br \/>\n                new ChangeListener<CustomerWrapper>() {<br \/>\n            @Override<br \/>\n            public void changed(ObservableValue<? extends CustomerWrapper> ov,<br \/>\n                    CustomerWrapper old_val, CustomerWrapper new_val) {<br \/>\n                txtName.setText(new_val.getDisplayName());<br \/>\n                txtCity.setText(new_val.getCustomer().getCity());<br \/>\n            }<br \/>\n        });<br \/>\n    }<br \/>\n}[\/java]<\/p>\n<p>Note that you will need a dependency on the CustomerDBAccessLibrary module from the sample app.<\/p>\n<p>The last step is add the code to display the JavaFX scene to the end of the constructor of the JavaFXWindowManager class:<\/p>\n<p>[java]        try {<br \/>\n            JFXPanel fxPanel = new JFXPanel();<br \/>\n            Parent root = FXMLLoader.load(JavaFXWindowManager.class.getResource(&#8220;crudwindow.fxml&#8221;));<br \/>\n            Scene scene = new Scene(root);<br \/>\n            fxPanel.setScene(scene);<br \/>\n            mMainWindow.add(fxPanel, BorderLayout.CENTER);<br \/>\n        }<br \/>\n        catch (IOException ex) {<br \/>\n            Exceptions.printStackTrace(ex);<br \/>\n        }[\/java]<\/p>\n<p>The complete project structure now looks like this:<\/p>\n<figure id=\"attachment_939\" aria-describedby=\"caption-attachment-939\" style=\"width: 258px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud14.png\"><img loading=\"lazy\" src=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud14.png\" alt=\"Completed Project\" width=\"268\" height=\"365\" class=\"size-full wp-image-939\" srcset=\"https:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud14.png 268w, https:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud14-220x300.png 220w\" sizes=\"(max-width: 268px) 100vw, 268px\" \/><\/a><figcaption id=\"caption-attachment-939\" class=\"wp-caption-text\">Completed Project<\/figcaption><\/figure>\n<p>And the running application:<\/p>\n<figure id=\"attachment_914\" aria-describedby=\"caption-attachment-914\" style=\"width: 630px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud08.png\"><img loading=\"lazy\" class=\"size-full wp-image-914\" alt=\"The new JavaFX GUI\" src=\"http:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud08.png\" width=\"640\" height=\"480\" srcset=\"https:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud08.png 640w, https:\/\/www.pellissier.co.za\/hermien\/wp-content\/uploads\/sites\/2\/2016\/06\/crud08-300x225.png 300w\" sizes=\"(max-width: 640px) 100vw, 640px\" \/><\/a><figcaption id=\"caption-attachment-914\" class=\"wp-caption-text\">The new JavaFX GUI<\/figcaption><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>I was honoured to present last weekend at the Java 9 and Women in Tech Unconference in Sandton, South Africa. The topic of the presentation was a JavaFX makeover for the NetBeans Platform &#8211; get the slides here. Today I want to share the details of the process of transforming the GUI of an existing &#8230; <a title=\"JavaFX makeover for the NetBeans Platform\" class=\"read-more\" href=\"https:\/\/www.pellissier.co.za\/hermien\/?p=880\" aria-label=\"More on JavaFX makeover for the NetBeans Platform\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"spay_email":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false},"categories":[8,3,4,5],"tags":[],"jetpack_featured_media_url":"","jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p1v8WL-ec","_links":{"self":[{"href":"https:\/\/www.pellissier.co.za\/hermien\/index.php?rest_route=\/wp\/v2\/posts\/880"}],"collection":[{"href":"https:\/\/www.pellissier.co.za\/hermien\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.pellissier.co.za\/hermien\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.pellissier.co.za\/hermien\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.pellissier.co.za\/hermien\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=880"}],"version-history":[{"count":52,"href":"https:\/\/www.pellissier.co.za\/hermien\/index.php?rest_route=\/wp\/v2\/posts\/880\/revisions"}],"predecessor-version":[{"id":943,"href":"https:\/\/www.pellissier.co.za\/hermien\/index.php?rest_route=\/wp\/v2\/posts\/880\/revisions\/943"}],"wp:attachment":[{"href":"https:\/\/www.pellissier.co.za\/hermien\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=880"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.pellissier.co.za\/hermien\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=880"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.pellissier.co.za\/hermien\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=880"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}