Reactive event streams, observable values and more for JavaFX.

Related tags

GUI ReactFX
Overview

ReactFX

ReactFX is an exploration of (functional) reactive programming techniques for JavaFX. These techniques usually result in more concise code, less side effects and less inversion of control, all of which improve the readability of code.

Initial inspiration came from the Principles of Reactive Programming course and the RxJava library. There are, however, important differences from RxJava.

Help and Discussion

Use reactfx tag on StackOverflow to ask specific questions. For more general discussions about the design of ReactFX and reactive programming for JavaFX, use the reactfx-dev mailing list.

Event Streams

An EventStream emits values (events). You can subscribe to an event stream to get notified each time a value is emitted.

interface EventStream<T> {
    Subscription subscribe(Consumer<T> consumer);
}

Example:

EventStream<T> eventStream = ...;
eventStream.subscribe(event -> System.out.println(event));

To stop receiving notifications, you use the Subscription returned from the subscribe method to unsubscribe:

Subscription subscription = eventStream.subscribe(event -> System.out.println(event));
// ...
subscription.unsubscribe();

Note that you need only the instance of Subscription to stop previously requested notifications. Compare this to JavaFX listeners/event handlers, where you need to keep both the listener/handler and the object you are listening to to be able to unregister the listener/handler.

Multi-valued streams

Multi-valued streams compensate for the lack of language support for tuples in Java. ReactFX has convenience classes for 2- and 3-valued streams, namely BiEventStream and TriEventStream. This allows you to write

BiEventStream<A, B> eventStream = ...;
eventStream.subscribe((a, b) -> f(a, b));

instead of

EventStream<Tuple2<A, B>> eventStream = ...;
eventStream.subscribe(tuple -> f(tuple._1, tuple._2));

Event Streams vs Observable Values

JavaFX has a representation of a time-varying value, namely ObservableValue. ObservableValue holds a value at any point in time. This value can be requested with getValue().

Events, on the other hand, are ephemeral—they come and go. You can only be notified of an event when it occurs;—it does not make sense to ask the event stream about the "current event".

JavaFX has means to compose observable values to form new observable values, either using the fluent API (methods of ObservableValue subclasses), or using the Bindings helper class. Some useful compositions of observable values are also provided by the EasyBind library.

JavaFX, however, does not have a nice way to compose streams of events. The user is left with event handlers/listeners, which are not composable and inherently side-effectful. EventStreams try to fill this gap.

Event Streams in JavaFX

Although it has no notion of an event stream, there are many event streams already hiding in JavaFX. ReactFX provides adapter methods to materialize them as EventStream instances.

UI events

Every Node is capable of emitting various types of events. We can obtain an event stream for each event type:

EventStream<MouseEvent> clicks = EventStreams.eventsOf(node, MouseEvent.MOUSE_CLICKED);
clicks.subscribe(click -> System.out.println("Click!"));

ObservableValue invalidations and changes

Every ObservableValue (e.g. property, binding) emits invalidations and changes. We can obtain the respective event streams:

ObservableValue<T> observable = ...;
EventStream<?> invalidations = EventStreams.invalidationsOf(observable);
EventStream<Change<T>> changes = EventStreams.changesOf(observable);
EventStream<T> values = EventStreams.valuesOf(observable);
EventStream<T> nonNullValues = EventStreams.nonNullValuesOf(observable);

The values stream above emits the new value every time the value changes. As opposed to the changes stream above, it avoids creating a Change instance in case we're not interested in the old value.

Custom event streams

EventSource is an event stream that emits precisely what you push into it.

EventSource<Integer> numbers = new EventSource<>();
numbers.subscribe(i -> System.out.println(i));
numbers.push(7); // prints "7"

Stream composition

Fun begins with combining streams into new streams.

filter

EventStream<MouseEvent> clicks = EventStreams.eventsOf(node, MouseEvent.MOUSE_CLICKED);
EventStream<MouseEvent> leftClicks = clicks.filter(click -> click.getButton() == MouseButton.PRIMARY);

map

EventStream<KeyEvent> keysTyped = EventStreams.eventsOf(node, KeyEvent.KEY_TYPED);
EventStream<String> charsTyped = keysTyped.map(keyEvt -> keyEvt.getCharacter());

merge

EventStream<T> stream1 = ...;
EventStream<T> stream2 = ...;
EventStream<T> merged = EventStreams.merge(stream1, stream2);

combine

EventStream<Double> widths = ...;
EventStream<Double> heights = ...;
EventStream<Double> areas = EventStreams.combine(widths, heights).map((w, h) -> w * h);

areas emits a combined value every time either widths or heights emit a value, but only after both widths and heights had emitted at least once.

zip

EventStream<Double> widths = ...;
EventStream<Double> heights = ...;
EventStream<Double> areas = EventStreams.zip(widths, heights).map((w, h) -> w * h);

areas emits a combined value every time both widths and heights emit a value. zip expects all input streams to emit values at the same frequency. In the above example, it would be an IllegalStateException if widths emitted twice while heights did not emit at all.

reduceSuccessions

Accumulates events emitted in close temporal succession into one.

EventSource<Integer> source = new EventSource<>();
EventStream<Integer> accum = source.reduceSuccessions((a, b) -> a + b, Duration.ofMillis(200));

source.push(1);
source.push(2);
// wait 150ms
source.push(3);
// wait 150ms
source.push(4);
// wait 250ms
source.push(5);
// wait 250ms

In the above example, an event that is emitted no later than 200ms after the previous one is accumulated (added) to the previous one. accum emits these values: 10, 5.

and more...

See the JavaDoc for more stream combinators.

Laziness of composite streams

All the adapters and combinators above subscribe lazily to their inputs - they don't subscribe to their inputs until they themselves have at least one subscriber. When the last subscriber unsubscribes, they unsubscribe from the inputs as well. This behavior has two benefits:

  1. unnecessary computation is avoided;
  2. composite stream's inputs don't prevent it from being garbage collected (no weak listeners needed).

Notice the difference to composed bindings. Bindings have to keep listening to their inputs all the time, because you can ask for the binding's current value (Binding.getValue()) any time. There is no such thing as the current value (event) of an event stream. This fact allows to automatically disconnect from the inputs when there are no subscribers.

Conversion to Binding

Every event stream can be converted to a Binding that reflects the most recent event emitted from the stream.

EventStream<T> stream = ...;
T initial = ...;
Binding<T> binding = stream.toBinding(initial);

initial is used as the value of binding until stream emits the first value.

binding maintains an active subscription to stream until its dispose() method is called.

Suspendable streams

SuspendableEventStream is an event stream whose event emission can be temporarily suspended. There are several types of suspendable event streams that differ in what events, if any, are emitted when their emission is resumed.

suppressible

When a suppressible stream is suspended, all events that would normally be emitted during this period are lost.

EventSource<Integer> src = new EventSource<>();
SuspendableEventStream<Integer> stream = src.suppressible();
stream.subscribe(i -> System.out.println(i));
stream.suspendWhile(() -> {
    src.push(1); // nothing is printed, 1 is never emitted from stream
});

pausable

When a pausable stream is suspended, events that would normally be emitted are buffered and emitted when event emission is resumed.

EventSource<Integer> src = new EventSource<>();
SuspendableEventStream<Integer> stream = src.pausable();
stream.subscribe(i -> System.out.println(i));
stream.suspendWhile(() -> {
    src.push(2);
    src.push(3);
    // nothing has been printed so far
});
// now "2" and "3" get printed

forgetful

When a forgetful stream is suspended, only the latest event that would normally be emitted is remembered. This event is emitted when event emission is resumed.

EventSource<Integer> src = new EventSource<>();
SuspendableEventStream<Integer> stream = src.forgetful();
stream.subscribe(i -> System.out.println(i));
stream.suspendWhile(() -> {
    src.push(4);
    src.push(5);
    // nothing has been printed so far
});
// now "5" gets printed

reducible

When a reducible stream is suspended, it keeps reducing the incoming events together. The result of reduction is emitted when event emission is resumed.

EventSource<Integer> src = new EventSource<>();
SuspendableEventStream<Integer> stream = src.reducible((a, b) -> a + b);
stream.subscribe(i -> System.out.println(i));
stream.suspendWhile(() -> {
    src.push(6);
    src.push(7);
    src.push(8);
    // nothing has been printed so far
});
// now "21" gets printed

Note that forgetful() is equivalent to reducible((a, b) -> b).

accumulative

When an accumulative stream is suspended, it keeps accumulating the incoming events into a cumulative value (accumulator), which may be of a different type than the events. When event emission is resumed, the accumulated value is deconstructed into a sequence of events that are emitted from the stream. This is a generalization of all previous suspendable streams.

reducible(reduction) can be modeled like this:

accumulative(t -> t, reduction, t -> Collections.singletonList(t))

suppressible() can be modeled like this:

accumulative(t -> (Void) null, (a, t) -> a, a -> Collections.emptyList())

pausable() can be modeled like this:

accumulative(ArrayList<T>::new, (l, t) -> { l.add(t); return l; }, l -> l)

InhiBeans

InhiBeans are extensions of bindings and properties from javafx.beans.* that help prevent redundant invalidations and recalculations.

See InhiBeans wiki page for details.

Indicator

Indicator is an observable boolean value that can be turned on temporarily.

Indicator workBeingDone = new Indicator();
Runnable work = ...;
workBeingDone.onWhile(work);

A useful use case for indicator is to signal when a component is changing state.

Consider a rectangle that needs to be repainted every time its width or height changes.

interface Rectangle {
    ObservableDoubleValue widthProperty();
    ObservableDoubleValue heightProperty();
    void setWidth(double width);
    void setHeight(double height);
}

Rectangle rect = ...;
rect.widthProperty().addListener(w -> repaint());
rect.heightProperty().addListener(h -> repaint());

rect.setWidth(20.0); // repaint #1
rect.setHeight(40.0); // repaint #2

Using indicator and stream combinators we can reduce the number of repaints in the above example to 1.

interface Rectangle {
    ObservableDoubleValue widthProperty();
    ObservableDoubleValue heightProperty();
    Indicator beingUpdatedProperty();
    
    // put implementation of setWidth() and setHeight() inside
    // beingUpdatedProperty().onWhile(/* implementation */);
    void setWidth(double width);
    void setHeight(double height);
}

Rectangle rect = ...;
EventStream<?> widthInvalidations = EventStreams.invalidationsOf(rect.widthProperty());
EventStream<?> heightInvalidations = EventStreams.invalidationsOf(rect.heightProperty());
EventStream<?> needsRepaint = EventStreams.merge(widthInvalidations, heightInvalidations);
EventStream<?> doneUpdating = beingUpdatedProperty().offs();
EventStream<?> repaintImpulse = needsRepaint.emitOn(doneUpdating);
repaintImpulse.subscribe(i -> repaint());

rect.beingUpdatedProperty().onWhile(() -> {
    rect.setWidth(20.0);
    rect.setHeight(40.0);
});
// just 1 repaint takes place now

Error handling

ReactFX has a mechanism to handle errors encountered by event streams. You can read more about this mechanism on the Error Handling wiki page.

Use ReactFX in your project

Stable release

Current stable release is 1.4.1.

Maven coordinates

Group ID Artifact ID Version
org.reactfx reactfx 1.4.1

Gradle example

dependencies {
    compile group: 'org.reactfx', name: 'reactfx', version: '1.4.1'
}

Sbt example

libraryDependencies += "org.reactfx" % "reactfx" % "1.4.1"

Manual download

Download the JAR file and place it on your classpath.

Milestone release

Current milestone release is 2.0-M5.

Maven coordinates

Group ID Artifact ID Version
org.reactfx reactfx 2.0-M5

Gradle example

dependencies {
    compile group: 'org.reactfx', name: 'reactfx', version: '2.0-M5'
}

Sbt example

libraryDependencies += "org.reactfx" % "reactfx" % "2.0-M5"

Manual download

Download the JAR file and place it on your classpath.

Snapshot releases

Snapshot releases are deployed to Sonatype snapshot repository.

Maven coordinates

Group ID Artifact ID Version
org.reactfx reactfx 2.0-SNAPSHOT

Gradle example

repositories {
    maven {
        url 'https://oss.sonatype.org/content/repositories/snapshots/' 
    }
}

dependencies {
    compile group: 'org.reactfx', name: 'reactfx', version: '2.0-SNAPSHOT'
}

Sbt example

resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"

libraryDependencies += "org.reactfx" % "reactfx" % "2.0-SNAPSHOT"

Manual download

Download the latest JAR file and place it on your classpath.

Links

API 1.4.1 (Javadoc)
API 2.0-M5 (Javadoc)

License

BSD 2-Clause License

Comments
  • Val.lazy() and Val.lazyAsync()

    Val.lazy() and Val.lazyAsync()

    See Issue 57

    An implementation and documentation for Val.lazy() is provided. It calls the given Supplier only once without notifing any observers. It is null-safe, but not thread-safe.

    An API is suggested for Val.lazyAsync(). Three variants are given. One merely gives a Callable to be executed in some other thread. Another gives the Executor to be used. Finally, a Supplier for a CompletionStage can be used as well. Together, these should provide for every case from maximum usability to maximum control.

    opened by Grannath 21
  • Ticks that restart their timer on Impulse

    Ticks that restart their timer on Impulse

    Coming from TomasMikula/RichTextFX#189, provide an additional ticks EventStream that will restart its timer whenever some other EventStream (impulse) emits an event.

    opened by JordanMartinez 17
  • Added prepend EventStream

    Added prepend EventStream

    I hope I've implemented the PrependEventStream correclty. I wasn't sure if it should be:

    return input.subscribe(e -> {
        event = hasEvent
                ? e
                : initial;
        hasEvent = true;
        emit(event);
    });
    

    or

    return input.subscribe(e -> {
        event = e != null
                ? e
                : initial;
        emit(event);
    });
    

    Both work, but I wasn't sure what the finer implications of one would be over the other in cases beyond the controlPressed case that initially made us think of writing this one.

    opened by JordanMartinez 15
  • subscribe: NoSuchMethodError

    subscribe: NoSuchMethodError

    Hi,

    I have come across the following exception:

    Caused by: java.lang.NoSuchMethodError: org.reactfx.EventStreamBase.subscribe(Ljava/lang/Object;)Lorg/reactfx/Subscription; at org.reactfx.BiEventSource.subscribe(BiEventSource.java:5)

    here is my code:

    BiEventSource<Metadata,Metadata> itemUpdateES = new BiEventSource();

    public Subscription subscribeToUpdates(BiConsumer<Metadata, Metadata> bc) { return itemUpdateES.subscribe(bc); }

    another exception that seems to have the same cause is:

    Caused by: java.lang.NoSuchMethodError: org.reactfx.MappedBiStream.subscribeToBi(Lorg/reactfx/BiEventStream;Ljava/util/function/BiConsumer;)Lorg/reactfx/Subscription; at org.reactfx.MappedBiStream.subscribeToInputs(MappedStream.java:46) at org.reactfx.LazilyBoundStream.firstSubscriber(LazilyBoundStream.java:17) at org.reactfx.EventStreamBase.subscribe(EventStreamBase.java:35) at org.reactfx.EventStreams$StreamBoundValueImpl.(EventStreams.java:689) at org.reactfx.EventStreams.toObservableValue(EventStreams.java:544) at org.reactfx.EventStream.toObservableValue(EventStream.java:72)

    thrown when used toObservableValue() on an event stream that is a result of : itemUpdateES.map((ov,nv)->nv).toObservableValue(value)

    Any thoughts?

    It looks like a problem with BiEventStreamBase implementation. I know i can always use BiTouple, but id rather not.

    Or am doing something wrong? Not sure why it is looking for subscribe(Object). Should the parameter not be a BiConsumer?

    edit: the problem turns out to be outdated .jar in the download section. Using the sources.jar directly does not cause any problems. The method toObservable() was apparently renamed to toBinding().

    opened by sghpjuikit 10
  • EventStreams#ticks emits its value at time 0 (timer start) or at its given interval (timer end).

    EventStreams#ticks emits its value at time 0 (timer start) or at its given interval (timer end).

    The only think to check would be FxTimer's factory methods' javadoc. I'm guessing you will think of a simpler way of explaining it.

    Note: I didn't implement ticks0 for non-"JavaFX Application" Threads.

    opened by JordanMartinez 9
  • Ticks that emits value at start, not end.

    Ticks that emits value at start, not end.

    Coming from TomasMikula/RichTextFX#189, provide additional ticks EventStream that emits its values at the start of its interval rather than the end of it.

    opened by JordanMartinez 8
  • TableView setCellValueFactory() goes crazy with EventStream binding

    TableView setCellValueFactory() goes crazy with EventStream binding

    Hey guys, I have found a problem in using reactive programming with JavaFX. The TableView TableColumn setCellValueFactory does not like being mapped to an EventStream binding. I noticed I can get an Observable in RxJava to work sometimes, but the moment any threads, schedulers, RxJava to ReactFX conversions, or Platform.runLater() calls are introduced chaos ensues. There is no way to effectively bring the subscription to the JavaFX thread without more complications. In many of these scenarios, the TableView keeps calling the cellValueFactory infinitely and re-emitting the values each time, but the values never make it to the table. Other times, no emissions make it at all.

    I've spammed SO with a few questions on the odd reactive behaviors I've been finding with TableView. TableColumn setCellValueFactory. Is there an easy solution for this?

    http://stackoverflow.com/questions/30804401/javafx-and-rxjava-tableview-infinitely-calling-setcellvaluefactory

    http://stackoverflow.com/questions/30931384/rxjava-javafx-property

    opened by thomasnield 8
  • Memory leak due to EventStreams.ticks and EventStream.emitOnEach(EventStream<?>)

    Memory leak due to EventStreams.ticks and EventStream.emitOnEach(EventStream)

    Hello,

    i use an EventStream which emit values on each tick of a "timer" stream:

    SimpleBooleanProperty property = new SimpleBooleanProperty(this, "test", true);
    EventStream<?> timerStream = EventStreams.ticks(ofMillis(10));
    EventStreams.valuesOf(property).emitOnEach(timerStream).subscribe(System.err::println);
    

    this cause a memory leak in my application, the FxTimer seems to be kept by the Toolkit. This is the output of the eclipse memory analyser.

    -----------------------------------------------------------------------------------------------------------------------------------------
    com.sun.javafx.tk.quantum.QuantumToolkit$$Lambda$48 @ 0x76eb0b328 Native Stack                                                           
    '- arg$1 com.sun.javafx.tk.quantum.QuantumToolkit @ 0x76eb103a8                                                                          
       '- animationRunnable com.sun.scenario.animation.AbstractMasterTimer$MainLoop @ 0x76ece3b10                                            
          '- this$0 com.sun.javafx.tk.quantum.MasterTimer @ 0x76eb7f068                                                                      
             '- receivers com.sun.scenario.animation.shared.PulseReceiver[2] @ 0x76eb7f0b8                                                   
                '- [0] javafx.animation.Animation$1 @ 0x76eb7f0d0                                                                            
                   '- this$0 javafx.animation.Timeline @ 0x76eb7f0e0                                                                         
                      '- clipCore com.sun.scenario.animation.shared.TimelineClipCore @ 0x76eb7f420                                           
                         '- keyFrames javafx.animation.KeyFrame[1] @ 0x76eb7f450                                                             
                            '- [0] javafx.animation.KeyFrame @ 0x76eb7f468                                                                   
                               '- onFinished org.reactfx.util.FxTimer$$Lambda$213 @ 0x76eb7f498                                              
                                  '- arg$1 org.reactfx.util.FxTimer @ 0x76eb7f4b0                                                            
                                     '- action org.reactfx.EventStreams$14$$Lambda$184 @ 0x76eb7f4d0                                         
                                        '- arg$1 org.reactfx.EventStreams$14 @ 0x76eb7f4e0                                                   
                                           '- observers org.reactfx.util.ListHelper$SingleElemHelper @ 0x76eb7f500                           
                                              '- elem org.reactfx.SuspendableBase$$Lambda$212 @ 0x76eb7f510                                  
                                                 '- arg$1 org.reactfx.PausableEventStream @ 0x76eb7f520                                      
                                                    '- observers org.reactfx.util.ListHelper$SingleElemHelper @ 0x76eb7f550                  
                                                       '- elem org.reactfx.SuspendWhenStream$$Lambda$211 @ 0x76eb7f560                       
                                                          '- arg$1 org.reactfx.SuspendWhenStream @ 0x76eb7f570                               
                                                             '- observers org.reactfx.util.ListHelper$SingleElemHelper @ 0x76eb7f598         
                                                                '- elem org.reactfx.EmitOnEachStream$$Lambda$209 @ 0x76eb7f5a8               
                                                                   '- arg$1 org.reactfx.EmitOnEachStream @ 0x76eb7f5b8                       
                                                                      '- observers org.reactfx.util.ListHelper$SingleElemHelper @ 0x76eb7f5e0
                                                                         '- elem org.reactfx.MappedStream$$Lambda$196 @ 0x76eb7f5f0          
                                                                            '- arg$1 org.reactfx.MappedStream @ 0x76eb7f600                  
    -----------------------------------------------------------------------------------------------------------------------------------------
    
    

    am i missing something ?

    opened by gontard 5
  • Converting a Var into a Val?

    Converting a Var into a Val?

    I have a Var used internally, and want to expose its value (read only) as a Val.

    It seems that this should be pretty trivial, but there is no method on Var to accomplish this directly:

     Var<Integer> var = Var.newSimpleVar(0);
     Val<Integer> val = var.asVal();
     // or:
     Val<Integer> val = var.readOnly();
    

    So for now I'm using:

     Val<Integer> val = var.orElseConst(0);
    

    Am I missing something obvious?

    opened by hjohn 4
  • Add javadoc to Val, StateMachine, and List-, Tuples-, and FingerTree-related classes and methods

    Add javadoc to Val, StateMachine, and List-, Tuples-, and FingerTree-related classes and methods

    WIP

    I figured I should document this first to better understand how it works since this is still the part of ReactFX I don't fully understand. Once I do, I'll better understand how Flowless works and thus how to solve some of its bugs.

    opened by JordanMartinez 4
  • Val.filer contains null if predicate is false

    Val.filer contains null if predicate is false

    Hi,

    I am using a Val bound to the text property of a TextField. I filter out strings which cannot be converted to LocalDateTime with a predicate in the string formatter

    Val.filter(this.textField.textProperty(), this.format::isValidDateTime)

    and them map the Val to LocalDateTime. In my program I start observing null values in the the Val when the isValidDateTime returns false. From the documentation of Val.filter, I would expect that values that do not satisfy the predicate are dropped and not replaced with null. However, I am not sure because I did not find a definition for an empty Val. Here is the code with the javadoc from

    /**
     * Returns a new {@linkplain Val} that holds the same value
     * as this {@linkplain Val} when the value satisfies the predicate
     * and is empty when this {@linkplain Val} is empty or its value
     * does not satisfy the given predicate.
     */
    default Val<T> filter(Predicate<? super T> p) {
        return filter(this, p);
    }
    
    static <T> Val<T> filter(
            ObservableValue<T> src,
            Predicate<? super T> p) {
        return map(src, t -> p.test(t) ? t : null);
    }
    

    It is obvious that values failing the predicate are substituted by null. Is that how it is supposed to work?

    opened by jens-auer 4
  • Weak Consumer references

    Weak Consumer references

    JavaFX has a few different WeakXXX wrappers for listeners. I currently need a similar thing for a Consumer that I can subscribe with, but that will automatically be removed if it's owners get garbage collected. LimitedInvocationSubscriber offers similar functionality, but with a different "reason" to revoke the subscription.

    opened by piegamesde 0
  • EasyBind vs ReactFX

    EasyBind vs ReactFX

    It's a bit unclear what's relation between EasyBind and ReactFX. Now I'm using both of them in my project, and only recently I've discovered that ReactFX contains Val/Var in addition to EventStream. Is ReactFX aiming to replace EasyBind?

    opened by cubuspl42 0
  • Implement dynamic list subscription and a list that tracks its elements

    Implement dynamic list subscription and a list that tracks its elements

    So there's something that I needed and I think it can be useful in the main repository. Changelog:

    • Add LiveList#flattenVals: basically this can be viewed as a transformation ObservableList<Val<T>> -> LiveList<T>, it "flattens" the Val context into the list. I guess the transformation would be functionally equivalent to _.flatMap(LiveList::wrapVal)
      • The returned list observes the changes of its individual elements and outputs them as ListChanges.
      • Example use case:
    LiveList<BlogEntry> entries = ...;
    
    // the size property is now also updated when any BlogEntry.wasReadProperty() changes value
    Val<Integer> readBlogs = entries.flattenVals(BlogEntry::wasReadProperty)
                                    .filter(Boolean::booleanValue)
                                    .sizeProperty();
    
    • The implementation needed implementing a dynamic subscription function for ObservableLists, which is in fact quite useful! I think that has the potential to e.g. simplify implementation of #53
    opened by oowekyala 0
  • how to pause

    how to pause

    How do I pause and resume using Timer ?

    I followed your approach in http://tomasmikula.github.io/blog/2014/06/04/timers-in-javafx-and-reactfx.html

    In javafx, I can do

    Timeline autosaveTimer = new Timeline(
    				new KeyFrame(Duration.seconds(60 * MINUTES),
    						ae -> masterClock.setSaveSim(DEFAULT))); 
    

    At some point I have to call autosaveTimer().pause() to pause

    and later call autosaveTimer().play() to resume

    In ReactFX, I do the following

    Timer autosaveTimer = FxTimer.runLater(
        				java.time.Duration.ofMinutes(60 * MINUTES),
        		        () -> masterClock.setSaveSim(DEFAULT)));
    

    I notice there is a stop() and restart() for Timer

    but I don't want to stop autosaveTimer completely and restart from the beginning of MINUTES. I want to resume from whatever MINUTES has elapsed.

    Is there a pause() and resume() that I can call ?

    opened by mokun 2
  • [enhancement] Some

    [enhancement] Some "min" and "max" methods for event stream.

    Hi, in a current project I use a lot "min" and "max" methods (like the methods from the java stream api). So in this project I wrote a small event stream extension with this methods but maybe there is the possibility to add these methods in a upcoming release/milestone/snapshot ;)

    default EventStream<T> min(Comparator<? super T> comparator) {
            return accumulate(BinaryOperator.minBy(comparator));
        }
    
     default EventStream<T> max(Comparator<? super T> comparator) {
            return accumulate(BinaryOperator.maxBy(comparator));
        }
    
    opened by schlegel11 0
Releases(v2.0-M5)
Owner
Tomas Mikula
Tomas Mikula
Reactive JavaFX Event Handling

ReactorFX This lightweight convenience library allows for simple integration between Project Reactor and JavaFX. ReactorFX provides fluent factories t

Jake 33 Dec 30, 2022
A simple JavaFX application to load, save and edit a CSV file and provide a JSON configuration for columns to check the values in the columns.

SmartCSV.fx Description A simple JavaFX application to load, save and edit a CSV file and provide a JSON Table Schema for columns to check the values

Andreas Billmann 74 Oct 24, 2022
Lifecycle-aware shared observable data holder class for android.

Eyejet Lifecycle-aware shared observable data holder class for android. 1. Depend on our library Eyejet Library is available through Maven Repository.

ZeoFlow 16 Jul 27, 2021
Functional Reactive Programming (FRP) for JavaFX

ReduxFX Functional Reactive Programming (FRP) for JavaFX ReduxFX in 1 minute ReduxFX is a set of libraries that enable you to use functional reactive

Michael Heinrichs 108 Oct 16, 2022
Composable event handlers and skin scaffolding for JavaFX controls.

This project is no longer being maintained. See this issue for more details. WellBehavedFX This project provides a better mechanism for defining and o

null 52 Oct 9, 2022
Lib-Tile is a multi Maven project written in JavaFX and NetBeans IDE 8 and provides the functionalities to use and handle easily Tiles in your JavaFX application.

Lib-Tile Intention Lib-Tile is a multi Maven project written in JavaFX and NetBeans IDE and provides the functionalities to use and handle easily Tile

Peter Rogge 13 Apr 13, 2022
DataFX - is a JavaFX frameworks that provides additional features to create MVC based applications in JavaFX by providing routing and a context for CDI.

What you’ve stumbled upon here is a project that intends to make retrieving, massaging, populating, viewing, and editing data in JavaFX UI controls ea

Guigarage 110 Dec 29, 2022
Tray Icon implementation for JavaFX applications. Say goodbye to using AWT's SystemTray icon, instead use a JavaFX Tray Icon.

FXTrayIcon Library intended for use in JavaFX applications that makes adding a System Tray icon easier. The FXTrayIcon class handles all the messy AWT

Dustin Redmond 248 Dec 30, 2022
Event-driven trigger + recording system for FFXIV

Triggevent Fully event driven trigger + overlay system for FFXIV. Makes triggers easier to develop and test. Allows triggers to have custom configurat

null 63 Dec 28, 2022
This app displays the perceived strength of a single earthquake event based on the DYFI indicator.

This app displays the perceived strength of a single earthquake event based on the DYFI indicator. Used in a Udacity course in the Android Basics Nanodegree.

Ezaz Ahammad 1 Jan 23, 2022
Old and archived; More recent development is in https://github.com/Create-Fabric/Create-Refabricated.

NOW ARCHIVED Go here for the continuation of this project. Old README Create Fabric A Fabric port of Create. Create Discord: https://discord.gg/AjRTh6

null 12 Dec 7, 2022
Source Code for 'More Java 17' by Kishori Sharan and Peter Späth

Apress Source Code This repository accompanies More Java 17 by Kishori Sharan and Peter Späth (Apress, 2021). Download the files as a zip using the gr

Apress 8 Oct 27, 2022
Lobby System Template for a multiplayer java game, with chat and other features, using JavaFX and socket TCP (will be extended to UDP).

JavaFX-MultiplayerLobbySystem JavaFX lobby system for multiplayer games with chat, ready toggle and kick buttons, using socket TCP by default. Demo Cr

Michele Righi 7 May 8, 2022
A Java framework for creating sophisticated calendar views (JavaFX 8, 9, 10, and 11)

CalendarFX A Java framework for creating sophisticated calendar views based on JavaFX. A detailed developer manual can be found online: CalendarFX 8 D

DLSC Software & Consulting GmbH 660 Jan 6, 2023
💠 Undecorated JavaFX Scene with implemented move, resize, minimise, maximise, close and Windows Aero Snap controls.

Support me joining PI Network app with invitation code AlexKent FX-BorderlessScene ( Library ) ?? Undecorated JavaFX Scene with implemented move, resi

Alexander Kentros 125 Jan 4, 2023
A JavaFX 3D Visualization and Component Library

FXyz3D FXyz3D Core: FXyz3D Client: FXyz3D Importers: A JavaFX 3D Visualization and Component Library How to build The project is managed by gradle. To

null 16 Aug 23, 2020
A collection of JavaFX controls and utilities.

GemsFX At least JDK 11 is required. Dialog Pane The class DialogPane can be used as a layer on top of any application. It offers various methods to di

DLSC Software & Consulting GmbH 269 Jan 5, 2023
A library for creating and editing graph-like diagrams in JavaFX.

Graph Editor A library for creating and editing graph-like diagrams in JavaFX. This project is a fork of tesis-dynaware/graph-editor 1.3.1, which is n

Steffen 125 Jan 1, 2023
📊 Exposing charts from Java to JavaFX and the Web!

Exposing charts from Java to JavaFX and to the Web! JavaFX · Charts · Websockets · Jetty · Web JavaFxDataviewer is an open-source data visualization t

jasrodis 57 Oct 26, 2022