Skip to content

Commit a9e03cf

Browse files
committed
Update README with new release features
1 parent 2dea19d commit a9e03cf

File tree

1 file changed

+82
-19
lines changed

1 file changed

+82
-19
lines changed

README.md

Lines changed: 82 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,9 @@ $ ./gradlew build
5454

5555
## Features
5656

57-
RxJavaFX has two sets of features:
57+
RxJavaFX has a lightweight set of features:
5858
- Factories to turn `Node` and `ObservableValue` events into an RxJava `Observable`
59+
- Factories to turn an RxJava `Observable` into a JavaFX `Binding`.
5960
- A scheduler for the JavaFX dispatch thread
6061

6162
###Node Events
@@ -68,7 +69,7 @@ Observable<ActionEvent> bttnEvents =
6869
```
6970

7071

71-
### ObservableValue Changes
72+
###ObservableValue
7273
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.
7374

7475
```java
@@ -77,9 +78,43 @@ TextField textInput = new TextField();
7778
Observable<String> textInputs =
7879
JavaFxObservable.fromObservableValue(textInput.textProperty());
7980
```
80-
8181
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.
8282

83+
###ObservableValue Changes
84+
85+
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.fromObservableValueChanges()` factory.
86+
```
87+
SpinnerValueFactory<Integer> svf = new SpinnerValueFactory.IntegerSpinnerValueFactory(0, 100);
88+
Spinner spinner = new Spinner<>();
89+
spinner.setValueFactory(svf);
90+
spinner.setEditable(true);
91+
92+
Label spinnerChangesLabel = new Label();
93+
Subscription subscription = JavaFxObservable.fromObservableValueChanges(spinner.valueProperty())
94+
.map(change -> "OLD: " + change.getOldVal() + " NEW: " + change.getNewVal())
95+
.subscribe(spinnerChangesLabel::setText);
96+
```
97+
98+
###Binding
99+
You can convert an RxJava `Observable` into a JavaFX `Binding` by calling the `JavaFxSubscriber.toBinding()` factory. Calling the `dispose()` method on the `Binding` will handle the unsubscription from the `Observable`.
100+
101+
```
102+
Button incrementBttn = new Button("Increment");
103+
Label incrementLabel = new Label("");
104+
105+
Observable<ActionEvent> bttnEvents =
106+
JavaFxObservable.fromNodeEvents(incrementBttn, ActionEvent.ACTION);
107+
108+
Binding<String> binding = JavaFxSubscriber.toBinding(bttnEvents.map(e -> 1).scan(0,(x, y) -> x + y)
109+
.map(Object::toString));
110+
111+
incrementLabel.textProperty().bind(binding);
112+
113+
//do stuff, then dispose Binding
114+
binding.dispose();
115+
116+
```
117+
83118
### JavaFX Scheduler
84119

85120
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.getInstance()` to another `observeOn()` afterwards to put it back on the JavaFX thread. From there it will update the `flippedTextLabel`.
@@ -106,52 +141,76 @@ If you are heavily dependent on RxJava, asynchronous processing, or do not want
106141

107142
## Comprehensive Example
108143
```java
144+
109145
import javafx.application.Application;
146+
import javafx.beans.binding.Binding;
110147
import javafx.event.ActionEvent;
111148
import javafx.scene.Scene;
112-
import javafx.scene.control.Button;
113-
import javafx.scene.control.Label;
114-
import javafx.scene.control.TextField;
149+
import javafx.scene.control.*;
115150
import javafx.scene.layout.GridPane;
116151
import javafx.stage.Stage;
117-
import rx.Observable;
118-
import rx.Subscription;
119152
import rx.observables.JavaFxObservable;
153+
import rx.schedulers.JavaFxScheduler;
154+
import rx.schedulers.Schedulers;
155+
import rx.subscribers.JavaFxSubscriber;
120156

121157
public class RxJavaFXTest extends Application {
122158

123159
private final Button incrementBttn;
124160
private final Label incrementLabel;
125-
private final Subscription sub1;
161+
private final Binding<String> binding1;
126162

127163
private final TextField textInput;
128164
private final Label fippedTextLabel;
129-
private final Subscription sub2;
165+
private final Binding<String> binding2;
166+
167+
private final Spinner<Integer> spinner;
168+
private final Label spinnerChangesLabel;
169+
private final Subscription subscription;
130170

131171
public RxJavaFXTest() {
132172

133173
//initialize increment demo
174+
//Turns button events into Binding
134175
incrementBttn = new Button("Increment");
135176
incrementLabel = new Label("");
136177

137178
Observable<ActionEvent> bttnEvents =
138179
JavaFxObservable.fromNodeEvents(incrementBttn, ActionEvent.ACTION);
139180

140-
sub1 = bttnEvents.map(e -> 1).scan(0,(x,y) -> x + y)
141-
.map(Object::toString)
142-
.subscribe(incrementLabel::setText);
181+
binding1 = JavaFxSubscriber.toBinding(bttnEvents.map(e -> 1).scan(0,(x, y) -> x + y)
182+
.map(Object::toString));
183+
184+
incrementLabel.textProperty().bind(binding1);
143185

144186
//initialize text flipper
187+
//Schedules on computation Scheduler for text flip calculation
188+
//Then resumes on JavaFxScheduler thread to update Binding
145189
textInput = new TextField();
146190
fippedTextLabel = new Label();
147191

148192
Observable<String> textInputs =
149193
JavaFxObservable.fromObservableValue(textInput.textProperty());
150194

151-
sub2 = textInputs.observeOn(Schedulers.computation())
195+
binding2 = JavaFxSubscriber.toBinding(textInputs.observeOn(Schedulers.computation())
152196
.map(s -> new StringBuilder(s).reverse().toString())
153-
.observeOn(JavaFxScheduler.getInstance())
154-
.subscribe(fippedTextLabel::setText);
197+
.observeOn(JavaFxScheduler.getInstance()));
198+
199+
fippedTextLabel.textProperty().bind(binding2);
200+
201+
//initialize Spinner value changes
202+
//Emits Change items containing old and new value
203+
//Uses RxJava Subscription instead of Binding just to show that option
204+
SpinnerValueFactory<Integer> svf = new SpinnerValueFactory.IntegerSpinnerValueFactory(0, 100);
205+
spinner = new Spinner<>();
206+
spinner.setValueFactory(svf);
207+
spinner.setEditable(true);
208+
209+
spinnerChangesLabel = new Label();
210+
subscription = JavaFxObservable.fromObservableValueChanges(spinner.valueProperty())
211+
.map(change -> "OLD: " + change.getOldVal() + " NEW: " + change.getNewVal())
212+
.subscribe(spinnerChangesLabel::setText);
213+
155214
}
156215

157216
@Override
@@ -168,8 +227,11 @@ public class RxJavaFXTest extends Application {
168227
gridPane.add(textInput,0,1);
169228
gridPane.add(fippedTextLabel, 1,1);
170229

230+
gridPane.add(spinner,0,2);
231+
gridPane.add(spinnerChangesLabel,1,2);
232+
171233
Scene scene = new Scene(gridPane);
172-
primaryStage.setWidth(265);
234+
primaryStage.setWidth(275);
173235
primaryStage.setScene(scene);
174236
primaryStage.show();
175237
}
@@ -178,8 +240,9 @@ public class RxJavaFXTest extends Application {
178240
public void stop() throws Exception {
179241
super.stop();
180242

181-
sub1.unsubscribe();
182-
sub2.unsubscribe();
243+
binding1.dispose();
244+
binding2.dispose();
245+
subscription.unsubscribe();
183246
}
184247
}
185248
```

0 commit comments

Comments
 (0)