One of the projects I worked on leading up to JavaOne 2011 was the DataFX project, which, as I wrote on the website, “is an open source project that intends to make retrieving, massaging, populating, viewing, and editing data in JavaFX UI controls easier. It’s all that boring kludge work you have to do between getting user requirements and delivering a rich user experience.”
DataFX is a project Johan Vos and I have been working on for many months now, and it has gone through a number of iterations in that time. At JavaOne 2011 we put out a first release (let’s call it version 0.0.1 for lack of an official version number), and today I want to briefly introduce it for those of you who didn’t attend JavaOne. However, even if you didn’t attend JavaOne, we’ve put the slides online.
To be very clear, DataFX is not an Oracle project! Johan and I both developed this in our own time, and it does not necessarily represent the future plans of the official JavaFX project. This project was built to make many of the UI controls I develop easier to work with by filling in the gaps as of the current JavaFX 2.0 release. Oracle may or may not have future plans in the same area as DataFX, but for now DataFX exists to fill the gap. For more details, check out the DataFX FAQ.
To make things easier to understand let’s conceptually split DataFX into two sub-projects which attack a common problem from two different angles.
The first sub-project deals with the logistics of getting data into the user interface controls by providing various data source adapters. These adapters are intended to provide convenience around populating JavaFX controls such as ListView and TableView (at this stage, although we’d love to eventually also support populating TreeView and charts). This is achieved by abstracting away the implementation details surrounding data source retrieval and massaging, such that data can be rapidly loaded and seen on screen. This is done by essentially creating data sources that are ObservableList instances, allowing for them to be directly loaded into the ListView and TableView ‘items’ property. In the case of TableView, DataFX can also auto-generate TableColumn instances with pre-built cell value factories defined.
DataSourceReader dsr1 = new FileReader("foo.xml"); DataSourceReader dsr2 = new NetworkReader ("http://foo.bar/foo.xml"); XmlDataSource ds1 = new XmlDataSource(dsr1); TableView tableView = new TableView(); tableView.setItems(ds1); tableView.getColumns().addAll(ds1.getColumns());
An example of how to use this API is shown above. We define two DataSourceReader instances: one is a FileReader, the other a NetworkReader (although in this example the NetworkReader isn’t used any further). In both cases it is important to note that the DataSourceReader is datatype-agnostic – that is, it only cares about where the data is coming from, not the format of the data. At present DataFX only ships with these two DataSourceReader implementations, but it is probable that over time we will add more classes. You can see the JavaDoc for these classes in the org.javafxdata.datasources.io package.
Once the DataSourceReader instance is created, we must then create a DataSource using one of the implementations provided in the org.javafxdata.datasources.protocol package. In the example below, we create an XmlDataSource, which knows how to parse an XML data stream and create an ObservableList that can be set directly into a ListView or TableView. Also, because it extends TableWrapper, it has a getColumns() method that can be used to set the columns in a TableView instance. At present, we have DataSource implementations for CSV files, Java Objects, RedFX and XML files. Again, we intend to add further data source implementations in the future as time permits.
Now that the DataSource exists, we create a TableView instance, and set the items property to be the data source itself. We also add all the columns the data source generates into the TableView columns property. This not only creates a column header with default text, it also creates a default cell value factory to populate the cells in that column. This is often the most complex part of using a TableView, and is completely unnecessary in data sources by default (of course, you are free to just create your own TableColumn instances also).
With a (by default) version number of 0.0.1, we recognise that DataFX is not a finished product. For one, it never will be – it’s a free project that we are making available here – but also we recognise the gaping holes in the data sources sub-project. In particular, along with what I’ve listed above, we also want to provide much more convenience around features such as sorting, filtering, and on-demand loading. If there is anything else that you think is missing, you can find the contact details over at the DataFX website.
The other sub-project of the DataFX project is dealing with the need to more easily visualise data once it is already appearing inside the ListView, TreeView and TableView controls. This customisation is done almost entirely using the cell factories API that is available in all three controls (I’ll try to blog more about cell factories in a future post). In other words, the default cell factory implementation provided by ListView/TreeView/TableView is sometimes not sufficient – it simply calls toString() on the data objects and shows it onscreen. In these circumstances, it is necessary to provide your own cell factory, and this is where DataFX comes in – it provides a number of useful cell factories that you can drop in and use, often with only one line of code.
There are a number of pre-built custom cells. You can see the full list on the cell factories page on the DataFX website, but briefly, it includes the following:
- TextField (for text editing)
- ChoiceBox (for selecting between a small number of choices)
- CheckBox (for toggling a boolean property)
- ProgressBar (for graphically representing a number as it progresses from 0.0 to 1.0)
- Money formatting (formats a Number instance using a default Locale, and applies CSS to make negative values red, and positive values green)
- Dynamically variable row heights (e.g. on mouse hover, a row will grow to show more information)
For each cell type mentioned above, there is a separate static factory class that contains a number of convenience methods. These methods should be your first port of call. You can find both the cells, and the more convenient cell factories API in the org.javafxdata.control.cell package. You should explore these javadocs as I have spent considerable effort ensuring that they contain all necessary information. For screenshots of all the cell factories currently available, you can go to the cell factories page on the DataFX website (clicking on the ticks will take you to a screenshot for that feature – I’ll try to make this more intuitive when I have time). I’ve attached one screenshot to this blog post, for the CheckBox TreeView.
In the code snippet below, I demonstrate how simple it is to make a ListView support text editing of cells when the user double-clicks on a row. In particular, note that the last line is the only line that uses the DataFX API (i.e. the reference to TextFieldCellFactory is from DataFX) – the other three lines are normal ListView API that should already be familiar to many developers.
ListView<String> listView = new ListView<String>(); listView.setItems(namesList); listView.setEditable(true); listView.setCellFactory(TextFieldCellFactory.forListView());
Again, the cell factories implementation certainly lacks features, but we think it provides a good starting point for the most common use cases. If there is a cell factory you think is missing, get in touch and let us know – we may just build it for you!
Johan and I both hope that DataFX is useful to you. We welcome feedback and requests for features – our goal is to make development of rich user interfaces in JavaFX 2.0 as simple as possible. Any use cases you can share with us will be much appreciated as we continue to refine our APIs, as well as provide additional data sources and cell factory implementations.