1

I am trying to create a custom Canvas widget under JavaFX, which gathers information from a lot of unrelated working threads. The "update" events might come in various rates, sometimes too fast and sometimes none at all, meaning that there is a need to properly address a "too fast update" and an "idle time" requirement. The number of updates is too high, so emitting a Runnable every time an update is performed is not a good solution.

Just for testing, my brute force approach was to create an AnimationTimer to update the visuals of the Canvas object. This solution works fine, but of course there are times that the Canvas doesn't need to be updated, making the whole procedure inefficient.

The closest answer to my problem seems to be this post with a GUIUpdater helper class, but Canvas seems not to have a direct update property. I am trying to find a way to "plug" the needed update functionality with the binded parameters, but with luck. I tried even to understand if Canvas has an "update" event, but I didn't find it. All other answers I found didn't meet the requirements - as far as I understand.

Thanks in advance

EDIT

Here is the code I use to make sure that only if the data changes, then the canvas will be drawn:

new AnimationTimer() {
    @Override
    public void handle(long now) {
        if (needsUpdate.getAndSet(false)) {
            myCustomCanvasRepaint();
        }
    }
}.start();

which is triggered with something like:

AtomicBoolean needsUpdate = new AtomicBoolean(true);
...
public void needsUpdate() {
    needsUpdate.set(true);
}
Community
  • 1
  • 1
Panayotis
  • 1,792
  • 23
  • 32
  • Related question on frequent updates: http://stackoverflow.com/questions/23488280/throttling-javafx-gui-updates – James_D Apr 12 '16 at 14:59
  • This might solve the "too frequent" but not the "idle" situation. I'll update my question to display what I did with a similar approach. – Panayotis Apr 12 '16 at 15:31
  • I'm not sure I understand what you mean by the "idle" situation – James_D Apr 12 '16 at 15:32
  • I mean that, there are times that there is a need for fast updates (more than the JavaFX can handle), but also times that no update is needed at all. There is not a constant flow of updates; only when needed. It is not the same situation as with the example. Here looks like it is more apropriate an event-like model instead? – Panayotis Apr 12 '16 at 15:40
  • I still don't get it. If the background thread in the example were idle, it wouldn't schedule any `Platform.runLater(...)` calls. – James_D Apr 12 '16 at 15:41
  • What if the background thread can not send (yet), since the JavaFX is still busy, and then goes to the idle state? Then the (last) update will not occur. I got your point though and I'll think about it a bit. – Panayotis Apr 12 '16 at 15:53

1 Answers1

0

This is really a duplicate of Throttling javafx gui updates, but you can do

private final AtomicBoolean updated = new AtomicBoolean();

// ...

Thread someBackgroundThread = new Thread(() -> {
    while (true) {
        waitArbitraryTimeForData() ;
        if (updated.getAndSet(false)) {
            updateCanvas();
        }
    }
});

private void updateCanvas() {
    Platform.runLater(() -> {
        updated.set(true);
        // repaint canvas...
    }
}

Depending on what data your updates rely on, you may need some additional locking of the data around the body of the Platform.runLater(). Or (probably better), represent the cumulative updates with an immutable class and replace the AtomicBoolean with an atomic reference to that class.

Community
  • 1
  • 1
James_D
  • 201,275
  • 16
  • 291
  • 322