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.

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