Featured Post

Applying Email Validation to a JavaFX TextField Using Binding

This example uses the same controller as in a previous post but adds a use case to support email validation.  A Commons Validator object is ...

Wednesday, October 22, 2014

JavaFX Tabbed Navigation

In today's touch-oriented desktop applications, tabbed navigation can provide a better user experience than heavyweight windows.  With a single-click on a tab, the user navigates to a new application view without shuffling a second modeless window.  Moreover, the tab allows the user to see the previous view and allows for quick switching between the tabs.

In JavaFX, a requirement like this is implemented using the TabPane class which contains a list of active Tabs.  In this demonstration, FXML from SceneBuilder will describe a whole tab structure and the program will manage the additional and removal of tabs from the pane.  

Note that there will only by one tab object of a kind in memory at one time.

Tab Pane


This video demonstrates a tabbed pane consisting of an un-closable Home and an About tab that is controlled through the menu and the close icon on the tab itself.

video

SceneBuilder and FXML

It's important in this implementation to use SceneBuilder to define as much of the UI as possible.  This is so that the fast authoring of FXML and CSS can rapidly prototype a UI and make that prototype usable in the development effort.   The FXML for this demo defines a TabPane that consists of all possible Tabs (in this case only 2, Home and About).  However, only Home will be shown initially.

A TabPane Containing Tabs in SceneBuilder

Code

I have a Controller class that is configured for the FXML shown in the previous figure.  This class has @FXML variables for all of the items of interest in all of the Tabs.  This includes the content TabPane, the Home Tab, and the About Tab.

    @FXML
    TabPane tabPane;
    
    @FXML
    Tab homeTab;
    
    @FXML
    Tab aboutTab;

The Controller also has an @FXML initialize() method.  This method removes the aboutTab from the tabPane where it was initially configured to be shown in the FXML.

tabPane.getTabs().remove( aboutTab );  // start w/o it showing

In the code for my MenuBar, I have an action that will add the aboutTab to the tabPane.  This is the crux of the implementation -- simple JavaFX Collections manipulations.  It checks to see if the Tab is there, if not, it will add it.  Note that there is only one aboutTab object ever.

if( !tabPane.getTabs().contains( aboutTab ) ) {
tabPane.getTabs().add( aboutTab );
}
tabPane.getSelectionModel().select(aboutTab);

The select() method makes the aboutTab the activeTab.

To hide the tab, I am using a new JavaFX 8 handler for the On Close Request event.  I remove the aboutTab from the TabPane and I consume the event to prevent the aboutTab object from being removed.

aboutTab.setOnCloseRequest(new EventHandler<Event>() {
@Override
public void handle(Event arg0) {
if( log.isDebugEnabled() ) {
log.debug("[ABOUT CLOSED]");
}
if( tabPane.getTabs().contains( aboutTab ) ) {
tabPane.getTabs().remove( aboutTab );
}
arg0.consume();
}
});

Memory Usage and Design

While the aboutTab is a relatively small in terms of RAM, it's worth noting that there is a potential performance benefit and a design benefit in maintaining a single object per tab.  The performance benefit comes from not having to create more objects than are needed using the show/hide versus create/destroy implementation.  Fewer file FXML accesses, Image loading, etc.

On the design side, this single-object approach has a bigger benefit in controlling program state.  The aboutTab object will always exist throughout my Application, so I never have to worry about NPEs when referencing aboutTab.  Moreover, I don't have to write code to manage the aboutTab object (creation, cleanup), simplifying the program state for testing and maintenance.

3 comments:

  1. Thank you ! I was looking for it.

    ReplyDelete
  2. how do i get the code?

    ReplyDelete
    Replies
    1. Hi,

      I don't have this particular example anymore. However, I put the full source up on GitHub for my later posts. https://github.com/bekwam/examples-javafx-repos1 has some examples you might find useful. Take a look at this web page for a summary of the repository: http://www.bekwam.com/learn.html.

      Good luck

      Delete