Reputation: 159
I've a ImageView within my view and try to display a WritableImage instance with it. I am drawing it within an outher thread and pass it to the view by listening to ObjectProperty's change event.
public void changed(ObservableValue<? extends Image> observable,
Image oldValue, Image newValue) {
this.imageView.setImage(newValue);
}
The imageView should be ready to recieve an image, it is shown by my mainView. But it is thrwoing an IllegalStateException from
Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4
Does anyone can explain this?
Upvotes: 0
Views: 239
Reputation: 209330
The exception basically tells you what the problem is: you are changing the state of part of the scene graph from a thread other than the FX Application Thread. The reason for this is that listener methods are invoked on the same thread that changes the property.
You have a couple of options for fixing this: one is to just use Platform.runLater(...)
. You can either do this in the listener:
public void changed(ObservableValue<? extends Image> observable,
Image oldValue, Image newValue) {
Platform.runLater(new Runnable() {
@Override
public void run() {
this.imageView.setImage(newValue);
}
});
}
or you can do the same thing to set the value of your property on the FX Application Thread.
You haven't shown much code, but it may also be possible for you to use a Task
to compute the Image. So instead of something like:
new Thread(new Runnable() {
@Override
public void run() {
WritableImage image = new WritableImage(...);
/// draw on image....
myImageProperty.set(image);
}
});
you can do something like
Task<Image> imageTask = new Task<Image>() {
@Override
public Image call() {
WritableImage image = new WritableImage(...);
// draw on image....
return image ;
}
});
imageTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
@Override
public void handle(WorkerStateEvent event) {
myImageProperty.set(imageTask.getValue());
}
});
new Thread(imageTask).start();
(This is much cleaner in Java 8; I posted Java 7 compatible code as you used that style in the question).
Here you avoid the low-level API (Platform.runLater()
), instead using one of the callback methods (setOnSucceeded
) from Task
, which is guaranteed to be called on the FX Application Thread.
Upvotes: 4