DataFXThe best way to get real-world data
into your JavaFX application
The MissionIn this session, you'll learn how to develop Enterprise Applications in JavaFX with
Real-World Services and Data.
We will show how the DataFX framework facilitates the process of data retrieval and rendering, and how it allows you to focus
on your application-specific logic.
Overview
OverviewDataSources Websocket
Cells
Flow
Use DataFX
Use DataFX
JSF View
Browser Desktop Client
Business Layer
Or m
aybe
mobil
e...
Server
Persistence
REST
Concurrency
Concurrency API
JavaFX is a single threaded toolkit
You should not block the platform thread
Rest calls may take some time...
...and could freeze the application
Do not do this at home!
DataFX Executor
Executor executor = new ObservableExecutor();ListView<Service<?>> list = new ListView<>();list.setCellFactory(new ServiceCellFactory());
list.itemsProperty().bind(executor.currentServicesProperty());
implementation of java.util.concurrent.Executor
bind your services to the view
DataFX Executorsupports title, message and progress for each service
supports Runnable, Callable, Service & Task
cancel services on the gui
Let‘s wait
void ConcurrentUtils.runAndWait(Runnable runnable)
T ConcurrentUtils.runAndWait(Callable<T> callable)
like SwingUtilities.invokeAndWait(...)
we will collect allconcurrent helper
methods here
Lambda Support
JDK 8 has Lambda and the awesome Stream APIMap and reduce your collections in parallelBut how to turn into the JavaFX application thread?
Lambda SupportStreamFX<T> streamFX = new StreamFX<>(myStream);
it is a wrapper
ObservableList<T> list = ...;streamFX.publish(list);
streamFX.forEachOrdered(final Consumer<ObjectProperty<? super T>> action)
this will happen in the application thread
DataSources
DataSources
Obtain data from a variety of sources, in a variety of formats and put the data in a JavaFX Observable or ObservableList Object.
Goal:
Variety of sources -> the DataReader abstracts this
Variety of formats -> the Converter abstracts this
**
1
11
*11
*1
DataSourcesData
Observable /ObservableList
DataFX
DataProvider
DataReader
Converter
DataReaderinterface DataReader<T> {
T get();
boolean next();
}
Easy to
implement!
RestSourceFileSourceJDCBSource We provide this implementations
- with builder API -
RestReaderRestSource restSource = new RestSource();restSource.setHost(“myhost”);RestSource.setConverter(...);restSource.setPath("user/" + uid);restSource.setConsumerKey(“mykey”); restSource.setConsumerSecret(“mysecret”);
RestSourceBuilder.create().host(“myhost”).converter(...).path(“user”).path(uid).consumerKey(“myKey”).consumerSecret(“mysecret”).build()
-or-
Data conversion
DataReader<T> has to provide data as an object of type T
Converter<U,T> consumes input as U, and provides data as T
Converterinterface Converter<T,U> { public void initialize(T input); public U get(); public boolean next();}
create your custom one
JSONConverter<T> implements Converter<InputStream, T>RestSource reads an InputStream, and will ask Converter to deliver instance(s) of T
DataProviderDataProviders populate JavaFX Observable and ObservableList instances
Data is added/changed on the JavaFX Application Thread only
Retrieval is done in a background thread, managable via an ExecutorPool
DataProvider
API distinction between ObjectDataProvider and ListDataProvider
Builders are provided: ObjectDataProviderBuilder
ListDataProviderBuilder
Usage
ObservableValue<T> dataProvider.getData();
Worker<T> dataProvider.retrieve().getValue();
DataProvider.setResultObjectProperty(o);
different
patterns f
or
different
developer
s
How to populate Observable o with the retrieved value via DataProvider<T> dataProvider?
or
or
DataProvider
DataProviders leverage the Observable capabilities: content is added when it is available
ListDataProvider will add entities to the resulting ObservableList as long as input can be read from the DataReader
DataProvider
Binding the ObservableList in a ListView will cause the ListView to be populated gradually
This can be leveraged in your application logic, i.e. First retrieve the most recent or important items
Writeback support
Starting in DataFX 2.0, it is possible to make changes to retrieved data, and send those changes back to the original datasource
UI
Obs
erva
ble
external Data DataFX
Challenges
We don't want to write-back all changes
In many cases, write-back is more complex than read, and not symmetrical
i.e. Authentication needed, different granularity
Writeback supportonly one additional class that handles the writeback...
ObjectDataProvider.setWriteBackHandler(WriteBackHandler h);
ListDataDataProvider.setAddEntryHandler(WriteBackHandler h);
...and you only need to implement one
method
ExampleDataReader<Person> dr = new JdbcSource(....);ListDataProvider<Person> lodp = new ListDataProvider(dr);
ObservableList<Person> myList = ...;lodp.setResultObservableList(myList);
lodp.setWriteBackHandler(new WriteBackHandler<Person>() {...});
ok, this is the part
we already know
adding writeback support
Examplelodp.setWriteBackHandler(new WriteBackHandler<Person>() {
@Override public WritableDataReader createDataSource(Person me) {
String statement = "UPDATE PERSON SET lastName=\'" + me.getLastName() + "\' WHERE firstName=\'" + me.getFirstName() + "\'";
JdbcSource<Person> dr = new JdbcSource(dbURL, statement, null);
dr.setUpdateQuery(true);return dr;
}}); simple implementation of jdbc
writeback support
Writeback supportRestSource and JDBCSource already implement WritableDataReader
Threading is dealt with by DataReader implementations
Support of transient field by using @WriteTransient
Controller API
JAVAFX APIIn JavaFX you should use FXML to define your viewsYou can define a controller for the view
Link from (FXML-) view to the controller
<HBox fx:controller="com.guigarage.MyController"> <TextField fx:id="myTextfield"/> <Button fx:id="backButton" text="back"/></HBox>
Controller APISome kind of inversion of control
Define the FXML in your controller class
Create a view by using the controller class
Supports more annotations for the view livecycle
convention over configuration
Controller API@FXMLController("Details.fxml")public class DetailViewController { @FXML private TextField myTextfield; @FXML private Button backButton; @PostConstruct public void init() { myTextfield.setText("Hello!"); }}
define the FXML file
default Java annotation
Controller API<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.control.*?><?import javafx.scene.layout.*?> <HBox spacing="10" alignment="bottom_right"> <TextField fx:id="myTextfield"/> <Button fx:id="backButton" text="back"/></HBox>
use JavaFX Scene Builder!
no controller class is set in
FXML
Controller API
Provides a factory for view creation
Inject all needed Nodes with @FXML
Supports @PostConstruct
View Context
Controller API support 2 contextsApplicationContextView Context
Inject context by using Annotation
Register your model to the context
View Contextpublic class DetailViewController { @FXML private TextField myTextfield; @FXMLViewContextprivate ViewContext<DetailViewController> context;
@PostConstruct public void init() { DataModel model = context.getViewFlowContext(). getRegisteredObject(DataModel.class);
myTextfield.textProperty(). bindBidirectional(model.getSelected()); }}
injection
access registered objects
ConclusionCreate view with FXML
Define your model as pojo
Create a controller
bind all this by using annotations
Flow API
Flow APIController API is good for one view
How to link different view?
Flow APIopenView View
View
View
View
View
search
details
open
diagram
setting*
Master Detailtwo views: master and detail
use FXML
switch from one view to the other one
delete data on user action
decoupling all this stuff!!
Master Detail
MasterView DetailsViewback
detailsdelete
Master Detail
MasterView DetailsViewback
details
FXML Controller FXML Controller
delete
Master Detail
FXMLFlowView masterView = FXMLFlowView.create(MasterViewController.class);
FXMLFlowView detailView = FXMLFlowView.create(DetailViewController.class);
create one FLowView for each view
use controller API internally
MasterView DetailsViewback
detailsdelete
Master Detail
detailView.withChangeViewAction("back", masterView);
direct link between the views
action name
MasterView DetailsViewback
detailsdelete
Master Detail
masterView.withRunAction("delete", DeleteAction.class);
define a custom action
action name
delete
MasterView DetailsViewback
detailsdelete
Master DetailUse controller API for all views
Define a FlowView for each view
link with by adding an action
add custom actions to your flow
but how can I use them?
Master Detail@FXMLController("Details.fxml")public class DetailViewController {
@FXML @FlowAction("back") private Button backButton; @PostConstruct public void init() { //... } @PreDestroy public void destroy() { //... }}
controller API
defined in FXML
bind your flow actions by annotation
listen to the
flow
Flow APIshare your data model by using contexts
ViewFlowContext added@FXMLViewFlowContextprivate ViewFlowContext context;
You can inject contexts in your
action classes, too
@PostConstruct and @PreDestroy are covered by the view livecycle
Flow APIBy using the flow API you don‘t have dependencies between the viewsReuse views and actions Use annotations for configuration
more stuff
Websocket APICell API
FileSource
www.javafxdata.org
https://bitbucket.org/datafx/datafx
https://bitbucket.org/datafx/javafxcommunity
QA
Top Related