RxJavaFX

by ReactiveX

ReactiveX / RxJavaFX

RxJava bindings for JavaFX

473 Stars 60 Forks Last release: 5 months ago (2.11.0-RC36) Apache License 2.0 332 Commits 62 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

RxJavaFX: JavaFX bindings for RxJava

Read the free eBook Learning RxJava with JavaFX to get started.

RxJavaFX is a lightweight library to convert JavaFX events into RxJava Observables/Flowables and vice versa. It also has a

Scheduler
to safely move emissions to the JavaFX Event Dispatch Thread.

NOTE: To use with Kotlin, check out RxKotlinFX to leverage this library with extension functions and additional operators.

Master Build Status

Documentation

Learning RxJava with JavaFX - Free eBook that covers RxJava from a JavaFX perspective.

Learning RxJava - Packt book covering RxJava 2.0 in depth, with a few RxJavaFX examples.

1.x Binaries

Binaries and dependency information for Maven, Ivy, Gradle and others can be found at http://search.maven.org.

Example for Maven:

    io.reactivex
    rxjavafx
    1.x.y

Gradle:

dependencies {
    compile 'io.reactivex:rxjavafx:1.x.y'
}

2.x Binaries

RxJavaFX 2.x versions uses a different group ID

io.reactivex.rxjava2
to prevent clashing with 1.x dependencies. Binaries and dependency information for Maven, Ivy, Gradle and others can be found at http://search.maven.org.

Example for Maven:

    io.reactivex.rxjava2
    rxjavafx
    2.x.y

Gradle:

dependencies {
    compile 'io.reactivex.rxjava2:rxjavafx:2.x.y'
}

Features

RxJavaFX has a comprehensive set of features to interop RxJava with JavaFX: - Factories to turn

Node
,
ObservableValue
,
ObservableList
, and other component events into an RxJava
Observable
- Factories to turn an RxJava
Observable
or
Flowable
into a JavaFX
Binding
. - A scheduler for the JavaFX dispatch thread

Node Events

You can get event emissions by calling

JavaFxObservable.eventsOf()
and pass the JavaFX
Node
and the
EventType
you are interested in. This will return an RxJava
Observable
.
Button incrementBttn = new Button("Increment");

Observable bttnEvents = JavaFxObservable.eventsOf(incrementBttn, ActionEvent.ACTION);

Action Events

Action events are common and do not only apply to

Node
types. They also emit from
MenuItem
and
ContextMenu
instances, as well as a few other types.

Therefore, a few overloaded factories are provided to emit

ActionEvent
items from these controls
Button ActionEvents
Button incrementBttn = new Button("Increment");

Observable bttnEvents = JavaFxObservable.actionEventsOf(incrementBttn);

MenuItem ActionEvents
MenuItem menuItem = new MenuItem("Select me");

Observable menuItemEvents = JavaFxObservable.actionEventsOf(menuItem);

Other Event Factories

There are also factories provided to convert events from a

Dialog
,
Window
or
Scene
into an
Observable
. If you would like to see factories for other components and event types, please let us know or put in a PR.

Dialogs and Alerts

Alert alert = new Alert(AlertType.CONFIRMATION);
alert.setTitle("Confirmation");
alert.setHeaderText("Please confirm your action");
alert.setContentText("Are you ok with this?");

JavaFxObservable.fromDialog(alert) .filter(response -> response.equals(ButtonType.OK)) .subscribe(System.out::println,Throwable::printStackTrace);

Emitting Scene Events
Observable sceneMouseMovements =
     JavaFxObservable.eventsOf(scene, MouseEvent.MOUSE_MOVED);

sceneMouseMovements.subscribe(v -> System.out.println(v.getSceneX() + "," + v.getSceneY()));

Emitting Window Hiding Events
 Observable windowHidingEvents =
    JavaFxObservable.eventsOf(primaryStage,WindowEvent.WINDOW_HIDING);

windowHidingEvents.subscribe(v -> System.out.println("Hiding!"));

ObservableValue

Not to be confused with the RxJava

Observable
, the JavaFX
ObservableValue
can be converted into an RxJava
Observable
that emits the initial value and all value changes.
TextField textInput = new TextField();

Observable textInputs = JavaFxObservable.valuesOf(textInput.textProperty());

Note that many Nodes in JavaFX will have an initial value, which sometimes can be

null
, and you might consider using RxJava's
skip()
operator to ignore this initial value.
ObservableValue Changes

For every change to an

ObservableValue
, you can emit the old value and new value as a pair. The two values will be wrapped up in a
Change
class and you can access them via
getOldVal()
and
getNewVal()
. Just call the
JavaFxObservable.changesOf()
factory.
SpinnerValueFactory svf = new SpinnerValueFactory.IntegerSpinnerValueFactory(0, 100);
Spinner spinner = new Spinner<>();
spinner.setValueFactory(svf);
spinner.setEditable(true);

Label spinnerChangesLabel = new Label(); Subscription subscription = JavaFxObservable.changesOf(spinner.valueProperty()) .map(change -> "OLD: " + change.getOldVal() + " NEW: " + change.getNewVal()) .subscribe(spinnerChangesLabel::setText);

ObservableList, ObservableMap, and ObservableSet

There are several factories to emit many useful

ObservableList
,
ObservableMap
, and
ObservableSet
events as Observables. These all can be found as static factory methods in the
JavaFxObservable
static class.

|Factory Method|Parameter Type|Return Type|Description| |---|---|---|--- |emitOnChanged()|ObservableList<T>|Observable<ObservableList<T>>|Emits the entire

ObservableList
every time it changes| |additionsOf()|ObservableList<T>|Observable<T>|Emits additions to an
ObservableList
| |removalsOf()|ObservableList<T>|Observable<T>|Emits removals from an
ObservableList
| |updatesOf()|ObservableList<T>|Observable<ListChange<T>>|Emits every item that was the result of a change to an
ObservableList
, with an
ADDED
,
REMOVED
, or
UPDATED
flag| |distinctChangesOf()|ObservableList<T>| Observable<ListChange<R>>|Emits only distinct addtions and removals to an
ObservableList
| |distinctMappingsOf()|ObservableList<T>, Func1<T,R>| Observable<ListChange<R>>|Emits only distinct additions and removals to an
ObservableList
and emits the mapping| |distinctChangesOf()|ObservableList<T>, Func1<T,R>| Observable<ListChange<R>>|Emits only distinct additions and removals to an
ObservableList
based on a mapping| |emitOnChanged()|ObservableMap<K,T>|Observable<ObservableMap<K,T>>|Emits the entire
ObservableMap
every time it changes| |additionsOf()|ObservableMap<K,T>|Observable<Map.Entry<K,T>>|Emits every
Map.Entry
added to an
ObservableMap
| |removalsOf()|ObservableMap<K,T>|Observable<Map.Entry<K,T>>|Emits every
Map.Entry
removed from an
ObservableMap
| |changesOf()|ObservableMap<K,T>|Observable<MapChange<K,T>>|Emits every key/value pair with an
ADDED
or
REMOVED
flag.| |emitOnChanged()|ObservableSet<T>|Observable<ObservableSet<T>>|Emits the entire
ObservableSet
every time it changes| |additionsOf()|ObservableSet<T>|Observable<T>|Emits every addition to an
ObservableSet
| |removalsOf()|ObservableSet<T>|Observable<T>|Emits every removal to an
ObservableSet
| |changesOf()|ObservableSet<T>|Observable<SetChange<T>|Emits every item
ADDED
or
REMOVED
item from an
ObservableSet
with the corresponding flag|

Binding

You can convert an RxJava

Observable
into a JavaFX
Binding
by calling the
JavaFxObserver.toBinding()
factory. Calling the
dispose()
method on the
Binding
will handle the unsubscription from the
Observable
. You can then take this
Binding
to bind other control properties to it.
Button incrementBttn = new Button("Increment");
Label incrementLabel =  new Label("");

Observable bttnEvents = JavaFxObservable.eventsOf(incrementBttn, ActionEvent.ACTION);

Observable accumulations = bttnEvents.map(e -> 1) .scan(0,(x, y) -> x + y) .map(Object::toString);

Binding binding = JavaFxObserver.toBinding(accumulations);

incrementLabel.textProperty().bind(binding);

//do stuff, then dispose Binding binding.dispose();

It is usually good practice to specify an

onError
to the
Binding
, just like a normal
Observer
so you can handle any errors that are communicated up the chain.
incrementLabel.textProperty().bind(binding, e -> e.printStackTrace());

Lazy Binding

The

toBinding()
factory above will eagerly subscribe the
Observable
to the
Binding
implementation. But if you want to delay the subscription to the
Observable
until the
Binding
is actually used (specifically when its
getValue()
is called), use
toLazyBinding()
instead.
Binding lazyBinding = JavaFxObserver.toLazyBinding(myObservable);

This can be handy for data controls like

TableView
, which will only request values for records that are visible. Using the
toLazyBinding()
to feed column values will cause subscriptions to only happen with visible records.

CompositeBinding

You also have the option to use a

CompositeBinding
to group multiple
Binding
s together, and
dispose()
them all at once. It is the JavaFX equivalent to
CompositeSubscription
.
Binding binding1 = ...
bindings.add(binding1);

Binding binding2 = ... bindings.add(binding2);

//do stuff on UI, and dispose() both bindings bindings.dispose();

JavaFX Scheduler

When you update any JavaFX control, it must be done on the JavaFX Event Dispatch Thread. Fortunately, the

JavaFxScheduler
makes it trivial to take work off the JavaFX thread and put it back when the results are ready. Below we can use the
observeOn()
to pass text value emissions to a computation thread where the text will be flipped. Then we can pass
JavaFxScheduler.platform()
to another
observeOn()
afterwards to put it back on the JavaFX thread. From there it will update the
flippedTextLabel
.
TextField textInput = new TextField();
Label fippedTextLabel = new Label();

Observable textInputs = JavaFxObservable.valuesOf(textInput.textProperty());

sub2 = textInputs.observeOn(Schedulers.computation()) .map(s -> new StringBuilder(s).reverse().toString()) .observeOn(JavaFxScheduler.platform()) .subscribe(fippedTextLabel::setText);

JavaFX Interval

There is a JavaFX equivalent to

Observable.interval()
that will emit on the JavaFX thread instead. Calling
JavaFxObservable.interval()
will push consecutive
Long
values at the specified
Duration
.
Observable everySecond = JavaFxObservable.interval(Duration.millis(1000));

Differences from ReactFX

ReactFX is a popular API to implement reactive patterns with JavaFX using the

EventStream
. However, RxJava uses an
Observable
and the two are not (directly) compatible with each other.

Although ReactFX has some asynchronous operators like

threadBridge
, ReactFX emphasizes synchronous behavior. This means it encourages keeping events on the JavaFX thread. RxJavaFX, which fully embraces RxJava and asynchronous design, can switch between threads and schedulers with ease. As long as subscriptions affecting the UI are observed on the JavaFX thread, you can leverage the powerful operators and libraries of RxJava safely.

If you are heavily dependent on RxJava, asynchronous processing, or do not want your entire reactive codebase to be UI-focused, you will probably want to use RxJavaFX.

Notes for Kotlin

If you are building your JavaFX application with Kotlin, check out RxKotlinFX to leverage this library through Kotlin extension functions.

Bugs and Feedback

For bugs, questions and discussions please use the Github Issues.

LICENSE

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.