MVC tutorial with the NetBeans Rich Client Platform (RCP) and JavaFX

This tutorial illustrates the creation of a small application based on the NetBeans Rich Client Platform (RCP), and JavaFx, which will monitor the prices of a few stocks and update the UI in real time as prices are updated.  The application will make use of SceneBuilder to create an main UI, and JavaFX property bindings in order to keep the UI up to date as the prices are updated.


The Model

First, lets start with the model, a Stock class which will simply consist of a ticker symbol and a name.

public class Stock {
    
    protected String symbol;
    protected String name;

    public Stock(String symbol, String name) {
        this.symbol = symbol;
        this.name = name;
    }

    public String getSymbol() {
        return symbol;
    }

    public String getName() {
        return name;
    }    
}

Next, the listener interface that we will need to implement in order to get updates on the prices.  The priceUpdated() method will be invoked whenever a new price arrives for a stock.


public interface StockPriceUpdatedListener {

    public void priceUpdated( Stock stock, double price );
    
}

The model will consist of a collection of stocks, each of which will be mapped to a StringProperty.  When a new stock is added to the model, a new StringProperty will be created and mapped to the specified stock.  The model implements the StockPriceUpdatedListener interface.  When a new price is received, the StringProperty for that Stock will be looked up and updated.

Note that in the model below that you need to be on the main JavaFx thread when you update a property!  For the purposes of this application the stock prices are arriving from a non-ui thread, so updating the property needs to be wrapped in a Platform.runLater() call which will put the update on to the ui-thread.


import com.mvc.stock.price.Stock;
import com.mvc.stock.price.StockPriceUpdatedListener;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class StockModel implements StockPriceUpdatedListener {
    
    protected Map<Stock, StringProperty> stocks = new HashMap<>();
    DecimalFormat df = new DecimalFormat("$##0.00");
    
    public StringProperty addStock( Stock stock ) {
        StringProperty property = stocks.get(stock);
        if( property == null ) {
            property = new SimpleStringProperty("");
            stocks.put(stock, property);
        }
        
        return property;
    }
    
    @Override
    public void priceUpdated(Stock stock, double price) {
        //Don't update the properties from a non-JavaFx-UI thread!
        Platform.runLater( () -> stocks.get(stock).setValue(df.format(price)));
    }    
}


The View

Next, the view for this application was designed with SceneBuilder.  The layout consists of a GridPane containing information about a few stocks, as well as a subscribe button which will trigger the monitoring of price information.

Screen Shot 2015-06-12 at 1.06.11 PM

SceneBuilder generated the following FXML code below, with the UI controller set to:

com.mvc.stock.ui.StockPriceController

Also note that the button has its onAction event defined to call the subscribeButtonClicked() method which will need to be implemented in the StockPriceController class.


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

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


<AnchorPane id="AnchorPane" prefHeight="197.0" prefWidth="233.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="com.mvc.stock.ui.StockPricePanelController">
    <children>
        <GridPane alignment="CENTER" gridLinesVisible="true" layoutX="14.0" layoutY="14.0">
            <columnConstraints>
                <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
            </columnConstraints>
            <rowConstraints>
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            </rowConstraints>
            <children>
                <Label text="MSFT" GridPane.halignment="RIGHT" GridPane.rowIndex="1">
                    <padding>
                        <Insets right="10.0" />
                    </padding>
                </Label>
                <Label alignment="CENTER" text="Stock" textAlignment="CENTER" GridPane.halignment="CENTER">
                    <padding>
                        <Insets right="10.0" />
                    </padding>
                    <font>
                        <Font name="System Bold" size="13.0" />
                    </font>
                </Label>
                <Label text="Last Price" GridPane.columnIndex="1" GridPane.halignment="CENTER">
                    <font>
                        <Font name="System Bold" size="13.0" />
                    </font>
                </Label>
                <Label text="EBAY" GridPane.halignment="RIGHT" GridPane.rowIndex="3">
                    <padding>
                        <Insets right="10.0" />
                    </padding>
                </Label>
                <Label text="AMZN" GridPane.halignment="RIGHT" GridPane.rowIndex="2">
                    <padding>
                        <Insets right="10.0" />
                    </padding>
                </Label>
                <Label fx:id="msftPriceLabel" GridPane.columnIndex="1" GridPane.rowIndex="1">
                    <padding>
                        <Insets left="10.0" />
                    </padding>
                </Label>
                <Label fx:id="amznPriceLabel" GridPane.columnIndex="1" GridPane.rowIndex="2">
                    <padding>
                        <Insets left="10.0" />
                    </padding>
                </Label>
                <Label fx:id="ebayPriceLabel" GridPane.columnIndex="1" GridPane.rowIndex="3">
                    <padding>
                        <Insets left="10.0" />
                    </padding>
                </Label>
            </children>
        </GridPane>
        <Button fx:id="subscribeButton" layoutX="136.0" layoutY="153.0" mnemonicParsing="false" onAction="#subscribeButtonClicked" text="Subscribe" />
    </children>
</AnchorPane>



The Controller

As mentioned above, the FXML file references StockPricePanelController as the UI’s controller.  The controller has 3 labels and a button defined which will be injected into the controller by annotating those fields with the @FXML annotation.  When the controller is first initialized it creates a new stock object for each stock and then binds the StringProperty of the StockModel to the StringProperty of its corresponding label.

Also, as previously stated, the controller will need to implement a method called subscribeButtonClicked() which was defined in the FXML above.  This method needs to be annotated with the @FXML annotation in order to be invoked when the subscribeButton is clicked.  When this action is invoked, the controller will subscribe to price data for the specified stocks.


import com.mvc.stock.price.Stock;
import com.mvc.stock.price.provider.IStockPriceProvider;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;

/**
 * FXML Controller class
 *
 */
public class StockPricePanelController implements Initializable {

    
    @FXML
    protected Label msftPriceLabel;
    
    @FXML
    protected Label amznPriceLabel;
    
    @FXML
    protected Label ebayPriceLabel;
    
    @FXML
    protected Button subscribeButton;
    
    protected StockModel stockModel;
    
    protected IStockPriceProvider provider;
    protected Stock msft = new Stock("MSFT", "Microsoft");
    protected Stock amzn = new Stock("AMZN", "Amazon");
    protected Stock ebay = new Stock("EBAY", "eBay");
    
    
    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        stockModel = new StockModel();
        //bind the string property from the model to the labels.
        msftPriceLabel.textProperty().bindBidirectional( stockModel.addStock(msft) );
        amznPriceLabel.textProperty().bindBidirectional( stockModel.addStock(amzn) );
        ebayPriceLabel.textProperty().bindBidirectional( stockModel.addStock(ebay) );
    }    

    public IStockPriceProvider getProvider() {
        return provider;
    }

    public void setProvider(IStockPriceProvider provider) {
        this.provider = provider;
    }

    @FXML
    public void subscribeButtonClicked( ActionEvent event ) {
        if( provider != null ) {
            provider.subscribeToPriceData(msft, stockModel);
            provider.subscribeToPriceData(amzn, stockModel);
            provider.subscribeToPriceData(ebay, stockModel);
        }
    }
    
}

The final piece is to tie JavaFX UI into the NetBeans module which this component is a part of.  In order to do this you will need to have a TopComponent defined for your module like in the example below.  Basically a TopComponent is a top level panel that is usually within a TabbedPane in the main UI.  The TopComponent class below uses the Lookup API to find an implementation of an IStockPriceProvider interface.  Next a JFXPanel is created, which is a Swing JPanel that can hold a JavaFX Scene.

Within the Platform.runLater() method, a new FXMLLoader is created which points to the location of the FXML file from above.  Once the loader has loaded the file, we can obtain a reference to the StockPricePanelController, and pass in the instance of the stockPriceProvider that was previously just looked up.

Finally, a new Scene is created,  added to the JFXPanel, and the JFXPanel is added to the Center position of the TopComponent.


public final class StockPriceTopComponent extends TopComponent {

    public StockPriceTopComponent() {
        initComponents();
        setName(Bundle.CTL_StockPriceTopComponent());
        setToolTipText(Bundle.HINT_StockPriceTopComponent());
        putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.TRUE);
        putClientProperty(TopComponent.PROP_DRAGGING_DISABLED, Boolean.TRUE);
        putClientProperty(TopComponent.PROP_UNDOCKING_DISABLED, Boolean.TRUE);
        
        
        IStockPriceProvider stockPriceProvider = Lookup.getDefault().lookup(IStockPriceProvider.class);
        if( stockPriceProvider == null ) {
            throw new IllegalStateException( "Provider is null");
        }        
        
        JFXPanel jfxPanel = new JFXPanel();

        //This needs to be set to make sure the JavaFx thread doesn't exit if the tab is closed.
        Platform.setImplicitExit(false);
        
        // create JavaFX scene
        Platform.runLater(() -> {
            Parent root;
            try {
                FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/mvc/stock/ui/StockPricePanel.fxml"));
                root = loader.load();
                StockPricePanelController controller = loader.getController();
                controller.setProvider(stockPriceProvider);
                
                Scene scene = new Scene(root);
                
                jfxPanel.setScene(scene);
            } catch (IOException ex) {
                Exceptions.printStackTrace(ex);
            }
        });
        add( jfxPanel, BorderLayout.CENTER );
    }

The resulting NetBeans application is shown below.

Screen Shot 2015-06-12 at 1.43.45 PM

twitter: @RobTerpilowski
t
witter: @LimitUpTrading

Automatically Sorting a JavaFX TableView

With the SortedList implementation of ObservableList, automatically sorting a JavaFX TableView nearly works out of the box. In fact, it does work out of the box as long as you are adding or removing items from the list. In these circumstances, the list and the accompanying TableView will automatically resort the data. The case where the data isn’t automatically resorted is if the data in the existing rows change, but no rows are added or removed from the list.

For example, I have a TableView displaying various price information about a list of stocks including the last price, and the percent change from yesterday’s closing price. I would like to sort the list based on percent change, from lowest to highest as the prices change in real-time.  However since the app just loads the stocks into the list once and then never adds or removes items from the list, the TableView only auto sorted on the initial load, but did not automatically sort as the prices were updated.

Fortunately the fix proved to be fairly minor and easy to implement.

To start with, the application uses a Stock POJO which contains the following properties to represent the data. An ObservableList of these POJOs will be the basis of the data that the TableView will render.

public class Stock implements Level1QuoteListener {

protected StockTicker ticker;

protected SimpleStringProperty symbol = new SimpleStringProperty("");

protected SimpleDoubleProperty bid = new SimpleDoubleProperty(0);

protected SimpleDoubleProperty ask = new SimpleDoubleProperty(0);

protected SimpleDoubleProperty last = new SimpleDoubleProperty(0);

protected SimpleDoubleProperty percentChange = new SimpleDoubleProperty(0);

protected SimpleIntegerProperty volume = new SimpleIntegerProperty(0);

protected SimpleDoubleProperty previousClose = new SimpleDoubleProperty(0);

protected SimpleDoubleProperty open = new SimpleDoubleProperty(0);

 

The first step is to implement a new Callback, tying it to the property we wish to sort in the table. When this property is updated it will trigger the table to resort itself automatically.

      Callback<Stock,Observable[]> cb =(Stock stock) -> new Observable[]{
        stock.percentChangeProperty(),
    };

 

The next step is to create a new ObservableList using the Callback above.

      ObservableList<Stock> observableList = FXCollections.observableArrayList(cb);
      observableList.addAll(stocks);

Finally the last step is to create a new SortedList using the ObservableList previously created and also passing in an implementation of a Comparator which will be used to determine how to sort the data.

      SortedList<Stock> sortedList = new SortedList<>( observableList, 
      (Stock stock1, Stock stock2) -> {
        if( stock1.getPercentChange() < stock2.getPercentChange() ) {
            return -1;
        } else if( stock1.getPercentChange() > stock2.getPercentChange() ) {
            return 1;
        } else {
            return 0;
        }
    });


    tickerTableView.setItems(sortedList);
}

That’s it. The video below illustrates the auto-sorting in action as the price of the stocks are updated in real-time.


twitter: @RobTerpilowski

Formatting Rows in a JavaFX TableView Using CSS Pseudo Classes

One strategy for formatting cells in a JavaFX TableView is to utilize CSS Pseudo classes and a TableRowFactory to select the appropriate class to style the row. Below is a screenshot of an applcation that is configured to monitor real time stock quotes. Each row displays price information for a single stock. I would like the rows to be colored based on the price change of the particular stock, with a red row representing a stock that is trading lower since the previous day, and a green row to represent a stock whose current price is higher than the previous day.

enter image description here

First the domain object which represents the Stock is below. Notice that the class uses JavaFX properties to represent the various values that are displayed in each column.

public class Stock implements Level1QuoteListener {

protected StockTicker ticker;
protected SimpleStringProperty symbol = new SimpleStringProperty();
protected SimpleDoubleProperty bid = new SimpleDoubleProperty();
protected SimpleDoubleProperty ask= new SimpleDoubleProperty();
protected SimpleDoubleProperty last = new SimpleDoubleProperty();
protected SimpleDoubleProperty percentChange = new SimpleDoubleProperty();
protected SimpleIntegerProperty volume = new SimpleIntegerProperty();
protected SimpleDoubleProperty previousClose = new SimpleDoubleProperty();
protected SimpleDoubleProperty open = new SimpleDoubleProperty();


public Stock( StockTicker ticker ) {
    this.ticker = ticker;
    setSymbol( ticker.getSymbol() );
}

public void setSymbol( String symbol ) {
    this.symbol.set(symbol);
}

public String getSymbol() {
    return symbol.get();
}

public StringProperty symbol() {
    return symbol;
}

public void setBid( double bid ) {
    this.bid.set(bid);
}

public double getBid() {
    return bid.get();
}

public SimpleDoubleProperty bid() {
    return bid;
}

public void setAsk( double ask ) {
    this.ask.set(ask);
}

public double getAsk() {
    return ask.get();
}

public DoubleProperty ask() {
    return ask;
}

public void setLast( double last ) {
    this.last.set(last);
    double change = ((last-closeProperty().get() ) / closeProperty().get() ) * 100.0;
    setPercentChange(change);

}

public double getLast() {
    return last.get();
}

public DoubleProperty last() {
    return last;
}

public void setPercentChange( double percentChange ) {
    this.percentChange.set(percentChange);
}

public double getPercentChange() {
    return percentChange.get();
}

public void setVolume( int volume ) {
    this.volume.set(volume);
}

public int getVolume() {
    return volume.get();
}

public void setPreviousClose( double close ) {
    this.previousClose.set(close);
    double change = ((last.get()-close ) / close ) * 100.0;
    setPercentChange(change);
}


public double getPreviousClose() {
    return previousClose.get();
}

public DoubleProperty previousClose() {
    return previousClose;
}

public void setOpen( double open ) {
    this.open.set(open);
}

public double getOpen() {
    return open.get();
}

public DoubleProperty openProperty() {
    return open;
}

public DoubleProperty closeProperty() {
    return previousClose;
}

public DoubleProperty percentChangeProperty() {
    return percentChange;
}

public StockTicker getTicker() {
    return ticker;
}



@Override
public void quoteRecieved(ILevel1Quote quote) {
    if( quote.getTicker().equals(ticker)) {
        BigDecimal quoteValue = quote.getValue();
        switch( quote.getType() ) {
            case ASK:
                setAsk(quoteValue.doubleValue());
                break;
            case BID:
                setBid(quoteValue.doubleValue());
                break;
            case LAST:
                setLast(quoteValue.doubleValue());
                break;
            case CLOSE:                  
                setPreviousClose(quoteValue.doubleValue());
                break;
            case OPEN:
                setOpen(quoteValue.doubleValue());
                break;
            case VOLUME:
                setVolume(quoteValue.intValue());
                break;
            default:
                break;

        }
    }
}

The first step in creating a custom format is to define the styles in the CSS stylesheet that is associated with the TableView. The CSS file below shows how the table row will be formatted. Comments below describe each item including the ‘up’ and ‘down’ Pseudo classes that are defined for the .table-row-cell class.

/* Default row background is black */
.table-row-cell {
    -fx-background-color: black;
}

/* Text in the rows will be white */
.table-row-cell .text {
       -fx-fill: white ;
}

/*
Pseudo class 'up' will change the row background
 color to green when activated 
 */
.table-row-cell:up 
{
    -fx-background-color: #007054; 
}

/*
Pseudo class 'down' will change the row background 
color to red when activated
*/
.table-row-cell:down {
    -fx-background-color: #A30029;
}

Ok, so far this seems easy enough. Now the tricky part is to activate the proper Pseudo class when the % change of the stock price is positive or negative. This can be done using a TableRowFactory in the controller class which is managing the TableView.

Below is an example controller which has a reference to a TableView object called tickerTableView. The setup() method contains logic for selecting the appropriate pseudo class based on the stock data.

public class FXMLController implements Initializable {


@FXML
private TableView tickerTableView;


 public void setup() {
 //The pseudo classes 'up' and 'down' that were defined in the css file.
    PseudoClass up = PseudoClass.getPseudoClass("up");
    PseudoClass down = PseudoClass.getPseudoClass("down");



//Set a rowFactory for the table view.
tickerTableView.setRowFactory(tableView -> {
        TableRow<Stock> row = new TableRow<>();
        ChangeListener<Number> changeListener = (obs, oldPrice, newPrice) -> {
            row.pseudoClassStateChanged(up, newPrice.doubleValue() > 0);
            row.pseudoClassStateChanged(down, newPrice.doubleValue() <= 0);
        };

        row.itemProperty().addListener((obs, previousStock, currentStock) -> {
            if (previousStock != null) {
                previousStock.percentChangeProperty().removeListener(changeListener);
            }
            if (currentStock != null) {
                currentStock.percentChangeProperty().addListener(changeListener);
                row.pseudoClassStateChanged(up, currentStock.getPercentChange() > 0);
                row.pseudoClassStateChanged(down, currentStock.getPercentChange() <= 0);
            } else {
                row.pseudoClassStateChanged(up, false);
                row.pseudoClassStateChanged(down, false);
            }
        });
        return row;
    });
}

The first step is to create 2 new PseudoClass object which will map to the Pseudo classes that were defined in the css file.

PseudoClass up = PseudoClass.getPseudoClass("up");
PseudoClass down = PseudoClass.getPseudoClass("down");

Next a RowFactory needs to be defined which knows how to select the proper PseudoClass. The setRowFactory() method on the TableView class takes a Callback object which in turn takes a TableView as an argument and returns a TableRow.

The first thing to do in the row factory is to create a new change listener. This listener will monitor the stock for a particular row. The oldPrice and newPrice are passed into the change listener. The pseudo class of the row can then be activated or deactivated by invoking the pseudoClassStateChanged() method on the TableRow and passing the appropriate PseudoClass and boolean value to indicate whether or not the class should be active.

tickerTableView.setRowFactory(tableView -> {
   TableRow<Stock> row = new TableRow<>();
   ChangeListener<Number> changeListener = (obs, oldPrice, newPrice) -> {
     row.pseudoClassStateChanged(up, newPrice.doubleValue() > 0);
     row.pseudoClassStateChanged(down, newPrice.doubleValue() <= 0);
   };

The final piece is to tie the change listener to the item in the TableRow. This is done by adding a listener on the ItemProperty of the row. Once a Stock item is added to the TableRow, the ChangeListener defined above can be bound to the Stock’s percentChangeProperty. The initial state of the classes are also set when the new item is added. If a Stock item is being removed from the TableRow, the previousStock variable will be populate with the Stock object that is being removed. At this point the change listener can be removed from the row for the old Stock before the new one is added.

row.itemProperty().addListener((obs, previousStock, currentStock) -> {
            if (previousStock != null) {
                previousStock.percentChangeProperty().removeListener(changeListener);
            }
            if (currentStock != null) {
                currentStock.percentChangeProperty().addListener(changeListener);
                //Set the initial state of the pseudo classes
                row.pseudoClassStateChanged(up, currentStock.getPercentChange() > 0);
                row.pseudoClassStateChanged(down, currentStock.getPercentChange() <= 0);
            } else {
                row.pseudoClassStateChanged(up, false);
                row.pseudoClassStateChanged(down, false);
            }
        });
        return row;
    });

The final result is displayed in the table below Rows will change between red and green automatically in real time as the price of the stock fluctuates throughout the trading day.

enter image description here

twitter: @RobTerpilowski

JavaFX Application Thread Mysteriously Disappearing in Netbeans RCP / JavaFX App

I have a fair amount of pluggable infrastructure in place with the NetBeans platform for trading related applications. My latest application, “Atlas Trader” is being used to route our commodity trades through Quantitative Brokers. I want to take advantage of JavaFX for this project as it provides a cleaner MVC separation than Swing does, and also provides a lot of eye candy out of the box, such as animated transitions, translucency, etc.). I have been having strange issues however when attempting to incorporate this as a module to my NetBeans platform application.

I started out with a stripped down version of the platform, since I don’t need any of the Swing components and all the UI components with be within an JavaFX Scene, so have only included the following RCP modules:

  • org-netbeans-api-annotations-common
  • org-openide-modules
  • org-openide-util
  • org-openide-util-lookup

In my module’s “Installer” class, the restored() method kicks off the JavaFX app with the following calls:

Application.launch(MainApp.class);
Platform.setImplicitExit(false);

Screen Shot 2015-04-10 at 11.07.51 AM

All seems to be ok at this point. The app launches and displays the UI correctly. I can log in and get to the main screen of the application.

Below is the main screen in the application. The issues arrises when one of the commodity labels at the top of the screen is clicked. The expected behaviour is to display a new JavaFX componenet allowing the user to enter an order.

Screen Shot 2015-04-10 at 11.13.21 AM

The “CommodityHeaderLabels” at the top of the UI have the following action method defined.

@FXML
public void fireCommodityClicked() {

When one of these headers are clicked, an exception is immediately thrown, complaining that:

Caused by: javafx.fxml.LoadException: 

/Users/RobTerpilowski/ZoiCapital/JavaSource/QTrader/ZQTrader-Plugin/target/classes/com/zoicapital/qtrader/plugin/TradePanel.fxml:15

at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2605)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2583)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2445)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2413)
at com.zoicapital.qtrader.plugin.TradePanel.init(TradePanel.java:198)
... 10 more

Caused by: java.lang.NullPointerException
at javafx.fxml.FXMLLoader.loadTypeForPackage(FXMLLoader.java:2920)

After drilling into the FXMLLoader class to find out what was going on, it appears that the “fireCommodityClick()” method is not being called from the JavaFX Event thread, and so it isn’t able to load the FXML file for the component that it needs to create when the item is clicked.

In fact, when running through the debugger, the JavaFX Thread is running prior to the component being clicked, but disappears when the component is clicked.

To make things even more difficult to understand, is that all the events leading up to this point are executed as expected in the RCP version of this application on the Java FX Application Thread. As I mentioned, I can log in to the application without any issues, and its not until one of these CommodityLabel components are clicked that the issue appears. Below is a screenshot of NB in the debugger with a breakpoint at the first line in the method that is called when the component is clicked. On the left side of the screen you can see the stack trace and that the current thread is the “AppKit Thread”, with the Java FX Application thread no longer present.

NB Screenshot

I set up a test project to run this application as a stand-alone outside of the NetBeans RCP, and things work as expected. The event method is called on the JavaFX Application Thread, and the resulting component is created and displayed as expected.

I can only think that there is an exception being swallowed somewhere, and that there may possibly be another NetBeans Platform module that is required in addition to the 4 modules that I mentioned at the beginning of this post.

I realize this post is a little short on the amount of code, but I’m looking for any other ideas on areas I could look at to further debug this issue.

twitter: @RobTerpilowski

JavaFX Toolkit Not Initialized (Solved)

I am attempting to utilize the NetBeans Rich Client Platform (RCP) as a shell to manage plugins for an automated trading application which uses JavaFX for the UI, but no Swing components. As such, I have a module installer class which creates the JavaFX scene, but no TopComponent class which RCP developers are accustom to using. The module class I have created is below.

import org.openide.modules.ModuleInstall;

public class Installer extends ModuleInstall {

@Override
public void restored() {
    Platform.setImplicitExit(false);

    // create JavaFX scene
    Platform.runLater(() -> {
        Parent root;
        try {
            FXMLLoader fxmlLoader = new FXMLLoader(MainScreen.class.getResource("/com/zoicapital/qtrader/plugin/BasePanel.fxml"));
            root = (Parent) fxmlLoader.load();
            Scene scene = new Scene(root);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    });
}

The problem is that when launching the application the following exception is being thrown.

java.lang.IllegalStateException: Toolkit not initialized
at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:273)
at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:268)
at javafx.application.Platform.runLater(Platform.java:83)
at com.zoicapital.qtrader.plugin.Installer.restored(Installer.java:22)

It turns out that even though Platform.runLater() is being invoked, it does not initialize the JavaFX runtime if it hasn’t already been started.

There are a couple of ways around the issue. The first is to invoke the Application.launch() method, or simply instantiate a new JFXPanel() class (even if it isn’t used for anything). Either action will cause the JavaFX Runtime to start and avoid initialization exception when the application is started.

StockChartsFX is Now Open Source

I have received several inquiries asking to provide examples on how I created the JavaFX candlestick chart that I have used in the trading apps that I am currently working on, pictured below. enter image description here I’ve done a bit of work to separate the chart out from the rest of the application and create a chart new library which I’ve open sourced at checked in to GitHub at: https://github.com/rterp/StockChartsFX The project includes both the JavaFX code as well as the style sheet used to style the component. There isn’t currently a lot of functionality built in to library, and the code is a bit messy, but contributions are welcome. twitter: @RobTerpilowski

Written with StackEdit.

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.