Make Money Online Automatically. Trading Commodities with JavaFX and the NetBeans Rich Client Platform

Ok, so maybe it isn’t quite as easy as it sounds, but we were able to leverage an automated trading application we had previously written and the modularity of the NetBeans Rich Client Platform to create a commodity trading application that will interface with, and allow us to place trades with a new commodity broker.

Even though the original application was for the purposes of automated trading, we were able to use many of the same NetBeans plugins we had developed in order to create the new application, as well as utilize JavaFX to put a nice polished UI on the app.

The login screen is below. The commodity images on the right side of the screen scroll down the UI and represent each commodity market that we trade.
enter image description here

After logging in to the application, those same commodities are in a dock at the top of the window. The images have an animated effect that will fade-in a green background when the mouse moves over the component. The first table in the UI shows orders that have been sent to the broker, but have not been fully executed, and the lower table displays commodity orders that have been completely executed.

enter image description here

After clicking on a commodity component at the top of the screen, the user is presented with a dialog to enter details about the order which will be placed. In the case of the screenshot below, an order is being entered to purchase 50 contracts of gold.

enter image description here

The last screenshot displays the state of the two main tables after orders to trade gold and natural gas have been fully executed, and while an order to purchase 50 Canadian Dollar futures contracts is still in process.

enter image description here

And finally, the 2 minute demo below highlights the application’s functionality as well as shows off the animated transitions and other eye candy that is possible using JavaFX. I will be speaking at JavaOne at a session entitled Flexibility Breeds Complexity: Living in a Modular World [CON6767], where I will discuss this and other JavaFX applications built on the NetBeans Rich Client Platform.

twitter: @RobTerpilowski

Written with StackEdit.

Animations with JavaFX: So Easy a Chimp Can Do It

Ok, well maybe its slightly more complicated than that, but not much. Things such as animations which were do-able with Swing, but were so painful, are baked into the JavaFX API and are relatively straightforward to implement.

In last month’s blog post, I demoed a JavaFX application which had 2 logos slowly scrolling across the app’s background. The code which was needed in order to acheive this effect was suprisingly minimal. The relevant code snippet from the application’s controller class is below.

public class AppController {

@FXML
protected ImageView logoImage;

@FXML
protected AnchorPane rootPane;

public void animateLogo() {
    TranslateTransition tt = 
    new TranslateTransition(Duration.seconds(30), logoImage);

    tt.setFromX( -(logoImage.getFitWidth()) );
    tt.setToX( rootPane.getPrefWidth() );
    tt.setCycleCount( Timeline.INDEFINITE );
    tt.play();
}
}

In the snippet above, we use a TranslationTransition which will move a node along a specified path over a specified time interval. The easiest way to do this is to give it the start point, end point, and the amount of time to run the animation for.

The TranslationTransition is created with a duration of 30 seconds, using the logoImage ImageView object that was injected by JavaFX into this controller class. Next, the starting point is set by specifying the fromX value on the transition. In this case, we want the animation to start the logo just off of the screen, so we specify a negative X value that is the width of the logo node. The toX value is set to the width of the entire UI so that the logo will scroll completely off the screen.

Finally, before playing the animation, the cycle count is set to INDEFINITE which means that as soon as the logo animation is complete, it will be automatically started again from the beginning, and keep doing so indefinitely.

That’s it, other transitions are equally as easy such as fading and scaling. Animations can also be chained together to run in sequence or set up to be run in parallel with other transitions.

Once again, from last month’s post, here’s a video showing animations in action. In particular, there are 2 logos which are animated on the Scene’s background that are scrolling in opposite directions across the screen.

 

Have fun!

twitter: @RobTerpilowski

Written with StackEdit.

Monitoring Real-Time Commodity Prices using JavaFX, NetBeans RCP, and Camel

Zoi Capital is a commodity investment firm which trades in the commodity futures markets on behalf of clients, with offices in New York and Seattle. We needed an application which could display the commodities we were currently holding as well as show any open profit/loss of our trades in real-time. In addition, we wanted to display the current performance of our trading strategy (named Telio) along with a comparison of the current performance of the S&P 500 stock index as well as the Dow Jones UBS commodity index.

Trades are placed from the Seattle office, but are monitored throughout the day from the New York office, so the application (which would be running in New York) needed a way to stay up to date with the current trades. The application also needed to be aesthetically pleasing as it was planned to put it on a large 50 inch LCD in the reception area of our New York office, where both staff and visitors could view the current trades and statistics in real time.

I had previously written an automated trading application on the NetBeans Rich Client Platform (RCP), where I had created a number of plug-ins, including a plug-in to connect to Interactive Brokers to retrieve real-time market data. Since I already had the plug-ins available in order to connect to a real-time data feed, it seemed a natural choice to also build the Quote Monitor application on the NetBeans RCP as well. Instead of using the existing Swing components however, I opted for JavaFX in order to give the application a polished look.

In order to get the trade information from the Seattle office to the Commodity Monitor application in the New York office, we made use of Camel to facilitate the communication between the 2 offices. The great thing about Camel is that it provides an abstraction layer for the actual communication mechanism between applications. Since the offices are not networked together we made use of the Camel email component in order to transfer the data from the Seattle office to the Commodity Monitor application. In the future we could move the communication mechanism to web services or JMS simply by changing a property file, with no code changes required as camel takes care of everything else under the hood.


System Architecture

enter image description here

Trades are placed in the Seattle office, and then emailed to a designated email box which the Commodity Monitor watches (via Camel). Trade information is then imported into the application, at which point it requests real-time quote information of the commodities from Interactive Brokers via their Java API. At this point the application can then update the profit/loss statistics in real-time.


Application Screen Shot

enter image description here

The grid in the top left portion of the screen displays the performance for our Telio trading strategy for today, for the month of August, and then the year-to-date return of the strategy. The table also shows the same statistics for the S&P 500 stock index and Dow Jones/UBS commodity index for comparison purposes.

Below the table is a candlestick chart displaying the performance of the S&P 500 Index futures for the current day. The chart made use of the charting API in JavaFX as well as CSS. The chart is updated in real-time throughout the day.

Finally, on the right half of the screen is a panel which displays the commodities that we are currently holding with current profit/loss on the trade. For example, we have a current profit of +0.18% since we bought natural gas.

To add additional eye candy to the application, I created a scrolling background with a slightly blurred Zoi Capital logo. The animation was extremely easy to set up in JavaFX, and I’ll post a short how-to blog on animations in the not-too-distant future.


Demo Video

Below is a 3 minute video demo showing the Commodity Monitor application with the animated scrolling background. About 40 seconds into the video an email is sent to the Camel email box, at which point the Commodity Monitor picks up the email and displays the commodities that were sent, and their corresponding profit/loss in real time. Another email is sent at the 2:10 mark that clears most of the commodities from the application.

 

twitter: @RobTerpilowski

Adding a Custom JavaFX Component to Scene Builder 2.0 (Part 2)

In a previous post I demonstrated how to add a custom component to Scene Builder 2.0 which was basically a short cut for copying & pasting FXML from the custom component into the FXML of the UI control which contained the component.

In this post I will demonstrate how to add a component as what I will call a ‘customized’ FXML component. Where the component will be encapsulated in its own custom FXML tag.

So to start off with, let’s say we have a label which contains a commodity name, image, and change in price. We’d like to have a collection of these commodity image labels on the main UI. Scene Builder is used to design the custom label (below):

enter image description here

Once the component is laid out, be sure that the “Use fxroot:construct” option is selected under the “Document” -> “Controller” accordion item on the left pane of Scene Builder.

enter image description here

In the project, for the custom component you should have the CommodityImageLabel.fxml file (the component just created in Scene Builder), and then create a CommodityImageLabel.java class to act as the component’s controller. (More on this in just a second)

enter image description here

First, a look below at the FXML code that was generated by Scene Builder

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.net.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.effect.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.text.*?>

<fx:root styleClass="glass-pane" type="AnchorPane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="110.0" prefWidth="675.0" styleClass="glass-pane" stylesheets="@zoi.css">
          <children>
              <Label fx:id="percentChangeLabel" layoutX="480.0" layoutY="14.0" text="- 0.23%" AnchorPane.rightAnchor="14.0">
                  <styleClass>
                      <String fx:value="label-text" />
                      <String fx:value="header" />
                  </styleClass>
              </Label>
              <Label fx:id="commodityLabel" layoutX="90.0" layoutY="28.0" text="Wheat">
                  <font>
                      <Font name="System Bold" size="50.0" />
                  </font>
                  <padding>
                      <Insets left="25.0" right="25.0" />
                  </padding>
                  <styleClass>
                      <String fx:value="label-text" />
                      <String fx:value="header" />
                  </styleClass>
              </Label>
              <Label fx:id="directionLabel" layoutX="120.0" layoutY="3.0" styleClass="label-direction-text" text="Long">
                  <opaqueInsets>
                      <Insets bottom="20.0" />
                  </opaqueInsets>
              </Label>
                <ImageView fx:id="commodityImageView" fitHeight="75.0" fitWidth="75.0" layoutX="14.0" layoutY="18.0" pickOnBounds="true" preserveRatio="true" AnchorPane.bottomAnchor="15.0" AnchorPane.leftAnchor="15.0" AnchorPane.topAnchor="15.0">
               <image>
                  <Image url="@../images/ZW.png" />
               </image></ImageView>
          </children>
      </AnchorPane>
   </children>
</fx:root>

Ok, on to the contorller class for the component.

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.zoicapital.commoditylabelwidget;

import java.io.IOException;
import java.text.DecimalFormat;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Label;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;

/**
 *
 * @author robbob
 */
public class CommodityImageLabel extends AnchorPane {

    @FXML
    protected Label directionLabel;

    @FXML
    protected Label commodityLabel;

    @FXML
    protected Label percentChangeLabel;

    @FXML
    private ImageView commodityImageView;

    protected DecimalFormat decimalFormat = new DecimalFormat("#0.00");
    protected String currentStyle = "";

    public CommodityImageLabel() {
        FXMLLoader fxmlLoader = new FXMLLoader(
                getClass().getResource("/fxml/CommodityImageLabel.fxml"));

        fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);

        try {
            fxmlLoader.load();
        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }

    }

    public void setPercentChange(double percentChange) {

        StringBuilder builder = new StringBuilder();
        String percentChangeString = decimalFormat.format(Math.abs(percentChange) * 100.0);
        String style;
        if ("0.00".equals(percentChangeString)) {
            style = Style.LABEL_PLAIN;
        } else {
            if (percentChange < 0) {
                builder.append("-");
                style = Style.LABEL_RED;
            } else {
                builder.append("+");
                style = Style.LABEL_GREEN;
            }
        }

        builder.append(percentChangeString);
        builder.append("%");

        percentChangeLabel.setText(builder.toString());

        if (!style.equals(currentStyle)) {
            getStyleClass().remove(currentStyle);
            currentStyle = style;
            getStyleClass().add(currentStyle);
        }

    }

}

 

First off, notice that it extends AnchorPane, and also that the constructor loads the component’s FXML and then tells the loader that ‘this’ will be acting as the component’s controller.
That’s it for creating the custom component. Build it, jar it up, and its ready to be imported into Scene Builder and used in an application.


Using the Custom Component in Scene Builder

The new application will need to include the previously created .jar file as a dependency, in this case the “CommodityLabelWidget.jar” file.

enter image description here

The DemoScreen.fxml component for this application currently looks as follows.

enter image description here

In order to get the CommodityImageLabel into Scene Builder’s pallete, select the small “gear” icon in the Library header of Scene Builder, and select the “Import JAR/FXML File…” item.
enter image description here

Next, browse to the .jar file that contains your custom component.
enter image description here

Once the .jar is selected, the import dialog should display a list of all the custom components in the .jar file. In this case the CommodityImageLabel is the only component available.

enter image description here

At this point the custom component is added to the Scene Builder pallette, and can be dragged on to the main UI.

enter image description here

Screen shot showing 2 CommodityImageLabels placed on the main application UI.

enter image description here

Now, in order to be able to access these custom component’s from your main UI’s controller class, enter an fx:id for the components in Scene Builder’s “Code” section for each component. Scene Builder may complain that it isn’t able to find an injectable field with the name you just entered, but don’t worry, you’ll be adding it to the UI’s controller shortly.
Save the .FXML file in Scene Builder and then head back over to the IDE.

enter image description here

Below is the FXML file generated by Scene Builder. Take note of the CommodityImageLabel “custom” FXML tags, also note that the controller for this class is “DemoScreenController” which is shown next.

<?xml version="1.0" encoding="UTF-8"?>

<?import com.zoicapital.commoditylabelwidget.*?>
<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>


<AnchorPane id="AnchorPane" prefHeight="632.0" prefWidth="889.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.zoicapital.demolabelproject.DemoScreenController">
   <children>
      <Label layoutX="72.0" layoutY="48.0" text="My Commodities">
         <font>
            <Font name="System Bold" size="36.0" />
         </font>
      </Label>
      <Separator layoutX="72.0" layoutY="109.0" prefHeight="4.0" prefWidth="289.0" />
      <CommodityImageLabel fx:id="commodityLabel1" layoutX="72.0" layoutY="144.0" />
      <CommodityImageLabel fx:id="commodityLabel2" layoutX="72.0" layoutY="268.0" />
   </children>
</AnchorPane>

In order to access the custom label components, be sure to name the fields the same as the fx:id controller name that you specified in Scene Builder, and to annotate the fields with the @FXML annotation.
Once this is complete you will have access to the CommodityImageLabel’s underlying controller classes, and can manipulate the custom component.

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package com.zoicapital.demolabelproject;

import com.zoicapital.commoditylabelwidget.CommodityImageLabel;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;

/**
 * FXML Controller class
 *
 * @author robbob
 */
public class DemoScreenController implements Initializable {


    @FXML
    protected CommodityImageLabel commodityLabel1;

    @FXML
    protected CommodityImageLabel commodityLabel2;

    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        commodityLabel1.setPercentChange(50.0);
        commodityLabel2.setPercentChange(-4.55);
    }    

}

The unfortunate wrinkle to this is that Scene Builder does not automatically pick up changes to the custom components. Meaning if you were to make a modification to the CommodityImageLabel component, you would need to manually re-import the .jar file in to Scene Builder in order to see the changes. This should hopefully be something that is addressed in a future version of Scene Builder.

twitter: @RobTerpilowski

Use JavaFX to Add Google Maps to your NetBeans RCP Application

By utilizing the GMapsFX library which provides a JavaFX API for Google Maps, it is relatively straightforward to add a map component to a desktop application built on the NetBeans Rich Client Platform (RCP).

Assume we would like to add a map to a new TopComponent in the Editor mode in the frame, or for those who are not as familiar with NetBeans jargon, we would like to add a Map to a new tab within the main portion of the application frame.

First create a new NetBeans Module project which will utilize the GMapsFX component.

enter image description here

Enter project details
enter image description here

Use RELEASE80 of the NetBeans Platform. Please also note that the application will require Java 8 in order to run.
enter image description here

Once the project has been created, add the GMapsFX library as a dependency to the project.
The binaries are available on Maven Central and the source is available at GitHub: https://github.com/rterp/GMapsFX
enter image description here

Once the dependency has been added, right click on the project in NetBeans and select “New” -> “Other”. Select the “Module Development” category and then select “Window” file type. This will create a new TopComponent class which will be used to host the map component.

 

enter image description here

Enter a prefix for the new TopComponent class.
enter image description here

Once this is finished a new GMapTopCompoent class will be created. The GoogleMapView component can then be added to this class in order to display the map.

Below is the code for the entire TopCompoment class including code in which I added the map component as well as a couple of map markers and an info window, all without having to interact with the underlying Google Maps JavaScript API.

package com.lynden.gmapsfx.module;

import com.lynden.gmapsfx.GoogleMapView;
import com.lynden.gmapsfx.MapComponentInitializedListener;
import com.lynden.gmapsfx.javascript.object.Animation;
import com.lynden.gmapsfx.javascript.object.GoogleMap;
import com.lynden.gmapsfx.javascript.object.InfoWindow;
import com.lynden.gmapsfx.javascript.object.InfoWindowOptions;
import com.lynden.gmapsfx.javascript.object.LatLong;
import com.lynden.gmapsfx.javascript.object.MapOptions;
import com.lynden.gmapsfx.javascript.object.MapTypeIdEnum;
import com.lynden.gmapsfx.javascript.object.Marker;
import com.lynden.gmapsfx.javascript.object.MarkerOptions;
import java.awt.BorderLayout;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import org.netbeans.api.settings.ConvertAsProperties;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.windows.TopComponent;
import org.openide.util.NbBundle.Messages;

/**
 * Top component which displays something.
 */
@ConvertAsProperties(
        dtd = "-//com.lynden.gmapsfx.module//GMap//EN",
        autostore = false
)
@TopComponent.Description(
        preferredID = "GMapTopComponent",
        //iconBase="SET/PATH/TO/ICON/HERE", 
        persistenceType = TopComponent.PERSISTENCE_ALWAYS
)
@TopComponent.Registration(mode = "editor", openAtStartup = true)
@ActionID(category = "Window", id = "com.lynden.gmapsfx.module.GMapTopComponent")
@ActionReference(path = "Menu/Window" /*, position = 333 */)
@TopComponent.OpenActionRegistration(
        displayName = "#CTL_GMapAction",
        preferredID = "GMapTopComponent"
)
@Messages({
    "CTL_GMapAction=GMap",
    "CTL_GMapTopComponent=GMap Window",
    "HINT_GMapTopComponent=This is a GMap window"
})


public final class GMapTopComponent extends TopComponent implements MapComponentInitializedListener {

    protected GoogleMapView mapComponent;
protected GoogleMap map;

public GMapTopComponent() {
    initComponents();
    setName(Bundle.CTL_GMapTopComponent());
    setToolTipText(Bundle.HINT_GMapTopComponent());
    setLayout(new BorderLayout());
    JFXPanel panel = new JFXPanel();
    Platform.setImplicitExit(false);

    Platform.runLater(() -> {
        mapComponent = new GoogleMapView();
        mapComponent.addMapInializedListener(this);
        BorderPane root = new BorderPane(mapComponent);
        Scene scene = new Scene(root);
        panel.setScene(scene);
    });

        add(panel, BorderLayout.CENTER);        

    }


  @Override
    public void mapInitialized() {
        //Once the map has been loaded by the Webview, initialize the map details.
        LatLong center = new LatLong(47.606189, -122.335842);



MapOptions options = new MapOptions();
        options.center(center)
                .mapMarker(true)
                .zoom(9)
                .overviewMapControl(false)
                .panControl(false)
                .rotateControl(false)
                .scaleControl(false)
                .streetViewControl(false)
                .zoomControl(false)
                .mapType(MapTypeIdEnum.ROADMAP);

        map = mapComponent.createMap(options);

        //Add a couple of markers to the map.
        MarkerOptions markerOptions = new MarkerOptions();
        LatLong markerLatLong = new LatLong(47.606189, -122.335842);
        markerOptions.position(markerLatLong)
                .title("My new Marker")
                .animation(Animation.DROP)
                .visible(true);

        Marker myMarker = new Marker(markerOptions);

        MarkerOptions markerOptions2 = new MarkerOptions();
        LatLong markerLatLong2 = new LatLong(47.906189, -122.335842);
        markerOptions2.position(markerLatLong2)
                .title("My new Marker")
                .visible(true);

        Marker myMarker2 = new Marker(markerOptions2);

        map.addMarker(myMarker);
        map.addMarker(myMarker2);

        //Add an info window to the Map.
        InfoWindowOptions infoOptions = new InfoWindowOptions();
        infoOptions.content("<h2>Center of the Universe</h2>")
                .position(center);

        InfoWindow window = new InfoWindow(infoOptions);
        window.open(map, myMarker);

    }    

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 300, Short.MAX_VALUE)
        );
    }// </editor-fold>                        

    // Variables declaration - do not modify                     
    // End of variables declaration                   
    @Override
    public void componentOpened() {
        // TODO add custom code on component opening
    }

    @Override
    public void componentClosed() {
        // TODO add custom code on component closing
    }

    void writeProperties(java.util.Properties p) {
        // better to version settings since initial version as advocated at
        // http://wiki.apidesign.org/wiki/PropertyFiles
        p.setProperty("version", "1.0");
        // TODO store your settings
    }

    void readProperties(java.util.Properties p) {
        String version = p.getProperty("version");
        // TODO read your settings according to their version


       }
    }

What is important to note is that no map related classes can be instantiated until the GoogleMapView has been initialized. This is because the underlying JavaScript peer objects can’t be created until the JavaScript runtime has been initialized. The TopComponent is added as a MapComponentInitializedListener so that it can determine when it is safe to begin manipulating the map and its associated objects.

This module is now ready to be included as a dependency in a NetBeans application in development, or be added as a plug-in to an existing Netbeans RCP application at runtime, or even added to the IDE itself.

One word of caution: The underlying JavaFX WebView and Javascript runtime which the GoogleMapView component is making use of to render the map appears to be a memory hog. I have had to play with memory settings in order to avoid OutOfMemoryErrors, so something to keep in mind as you play with this.

Below is the final product of running the GMapsFX plug-in within a NetBeans RCP application.

enter image description here

The GMapsFX project is open source with the project home at GitHub as mentioned above and can be accessed at:
http://rterp.github.io/GMapsFX/

twitter: @RobTerp

Adding Custom JavaFX Components to Scene Builder 2.0

With the release of Scene Builder 2.0 it is now much easier to add custom and 3rd party JavaFX controls to the component palette.

There are a couple of different strategies to add a custom component to Scene Builder, and this blog post will illustrate creating a custom component with FXML and importing the FXML file into Scene Builder so the custom component can be used within Scene Builder itself.

To start with, I’ll create a simple custom component in Scene Builder which will consist of a Button and a Label, which I have cleverly named a ButtonLabel. A screenshot of Scene Builder with the fancy new custom component is below.

enter image description here

Below is the FXML that SceneBuilder generates. As you can see I have an action defined on the button, but no controller defined for the component. This is because the button will end up pointing to whatever controller the Scene that this component gets bundled into. The other thing to note is that this FXML file contains no references to stylesheets or outside images.

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml" fx:controller="">
    <children>
        <Button layoutX="126" layoutY="90" text="Click Me!" onAction="#handleButtonAction" fx:id="button" />
        <Label layoutX="126" layoutY="120" minHeight="16" minWidth="70" fx:id="label" />
    </children>
</AnchorPane>

Now to add the new component to Scene Builder so it can be added to an application, you must import the FXML file into Scene Builder by selecting the icon next to the search box at the top of the Library Pane.

enter image description here

Browse the the FXML file of the custom component.
enter image description here

The ButtonLabel now appears in the Custom section of the library and can be dragged onto the new Scene.
enter image description here

Below is the code that is generated by Scene Builder for the new Scene with the LabelButton. As can be viewed below, Scene Builder simply imports the custom FXML code into the new scene, and also adds the #handleButtonAction to the com.lynden.myapp.FXMLController class.

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="379.0" prefWidth="442.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="com.lynden.myapp.FXMLController">
    <children>
        <TableView layoutX="40.0" layoutY="28.0" prefHeight="200.0" prefWidth="356.0">
            <columns>
                <TableColumn prefWidth="75.0" text="C1" />
                <TableColumn prefWidth="75.0" text="C2" />
            </columns>
        </TableView>
        <AnchorPane id="AnchorPane" layoutX="108.0" layoutY="256.0" prefHeight="109.0" prefWidth="220.0">
            <children>
                <Button fx:id="button" layoutX="172.0" layoutY="43.0" onAction="#handleButtonAction" text="Click Me!" AnchorPane.rightAnchor="10.0" />
                <Label fx:id="label" layoutX="14.0" layoutY="31.0" minHeight="16" minWidth="69" prefHeight="47.0" prefWidth="100.0" text="Custom Text" />
            </children>
        </AnchorPane>
    </children>
</AnchorPane>

twitter: @RobTerp

GMapsFX Version 1.1.0

GMapsFX 1.1.0 has been released and supports the following new features and bug fixes.

We are at also looking at breaking the Java-to-JavaScript abstraction layer out of this project and creating its own project for it, as this layer could prove useful for interacting with other JavaScript applications within a JavaFX WebView.

We will have project artifacts published to Maven Central in the very near future.

The latest GMapsFX.jar file can be found here

Project documentation can be found here and with Javadocs located here