0

I am very new to JavaFX.
I am working on an application where I have several GUI components which change appearance based on several data values. For example, there might be 3 traffic light components displayed which each change color based on the settings of three different pieces of data, let's call them light1, light2, and light3. The component has a function called updateColor(int data) which will update the color accordingly.

There is a separate thread running which periodically gets the data values and updates the values in light1, light2, and light3.

Now I would like the displayed components to automatically change colors as soon as the separate thread updates those values.

I have read about binding, but none of the examples I've seen seem to address this situation. Any ideas or pointers to some similar examples would be appreciated.

  • Possible duplicate of [Constantly Update UI in Java FX worker thread](http://stackoverflow.com/questions/20497845/constantly-update-ui-in-java-fx-worker-thread) – fabian Oct 04 '16 at 14:00

1 Answers1

3

If the values are being updated in a background thread, you cannot bind properties of the UI components to them, as this would result in the UI properties being updated in the background thread. Properties of nodes that are part of the scene graph can only be updated on the FX Application Thread.

One idiom for managing this is to register a listener with the properties, and update the UI from a call to Platform.runLater(...) when it changes. Assuming, say, light1 is an instance of a Property<T> for some type T this would look like

light1.addListener((obs, oldValue, newValue) -> 
    Platform.runLater(() -> {
        // update UI with newValue...
    }));

The alternative here is to let the background thread update the properties on the FX Application Thread; i.e. the background thread invokes Platform.runLater(...) to update the properties. Then, since the properties are only being changes on the FX Application Thread, it is safe to bind UI properties to them:

// background thread code:

public void run() {

    // ...

    // periodically update light1 on FX Application Thread:
    Platform.runLater(() -> light1.set(...));

}

and then you can do

someUIElement.someProperty().bind(light1);

(or replace light1 with some binding that is derived from light1).

For more general strategies for integrating background services into JavaFX, see the excellent article by Adam Bien.

James_D
  • 201,275
  • 16
  • 291
  • 322
  • Thanks, I'll take a look into that. – Mountain Dew Fan Oct 04 '16 at 15:13
  • Well one of the problems is that the background thread does not know about the GUI. It's job is just to get the values from the external source and store them locally. – Mountain Dew Fan Oct 05 '16 at 17:04
  • I'm not sure I understand. You said the separate thread "periodically gets the data values and updates the values in light1, light2, and light3". So, assuming you make those properties accessible externally you can just use the first solution (`light1.addListener((...) -> Platform.runLater(...));`), no? Or you can use the callback techniques in Adam's article. – James_D Oct 05 '16 at 18:00
  • Oh, OK. Got it. Thanks. – Mountain Dew Fan Oct 05 '16 at 20:31