Quelle est la meilleure façon de gérer le multithreading dans JavaFX 8?

J'essaie de trouver un moyen efficace d'influencer la forme et le contenu de la JavaFX les éléments d'interface graphique, comme simple Pane, avec l'utilisation du multithreading. Disons que j'ai un simple Pane, sur lequel j'ai d'affichage rempli Circles à la itervals de temps, et je veux avoir la possibilité de réponse, par exemple en appuyant sur la touche correspondante. Jusqu'à présent, à cette fin, j'ai essayé d'utiliser la classe avec la mise en œuvre de Runnable de l'interface et de la création de classique Thread objet, afin d'ajouter et/ou supprimer des éléments de l'extérieur, JavaFX Pane, qui a été adoptée pour que "la classe thread" dans son paramètre du constructeur de la principale Application classe. Dire, en deux classes, 1) et 2) de la classe thread, ressemble à ceci:

import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class ClassApplication extends Application {
private Pane pane;
public Parent createContent() {
/* layout */
BorderPane layout = new BorderPane();
/* layout -> center */
pane = new Pane();
pane.setMinWidth(250);
pane.setMaxWidth(250);
pane.setMinHeight(250);
pane.setMaxHeight(250);
pane.setStyle("-fx-background-color: #000000;");
/* layout -> center -> pane */
Circle circle = new Circle(125, 125, 10, Color.WHITE);
/* add items to the layout */
pane.getChildren().add(circle);
layout.setCenter(pane);
return layout;
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.setWidth(300);
stage.setHeight(300);
stage.show();
/* initialize custom Thread */
ClassThread thread = new ClassThread(pane);
thread.execute();
}
public static void main(String args[]) {
launch(args);
}
}

...et la "classe thread"

import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
public class ClassThread implements Runnable {
private Thread t;
private Pane pane;
ClassThread(Pane p) {
this.pane = p;
t = new Thread(this, "Painter");
}
@Override
public void run() {
try {
Thread.sleep(2000);
Circle circle = new Circle(50, 50, 10, Color.RED);
pane.getChildren().clear();
pane.getChildren().add(circle);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
public void execute() {
t.start();
}
}

Toutefois, une telle solution, où, en application Swing pourrait être possible, en JavaFX est impossible, et en plus, c'est la raison de l'exception suivante:

Exception in thread "Painter" java.lang.IllegalStateException: Not on FX application thread; currentThread = Painter
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(Unknown Source)
at javafx.scene.Parent$2.onProposedChange(Unknown Source)
at com.sun.javafx.collections.VetoableListDecorator.clear(Unknown Source)
at ClassThread.run(ClassThread.java:21)
at java.lang.Thread.run(Unknown Source)

...où la ligne "21" est: pane.getChildren().clear();

J'en ai conclu que "il y a un problème avec influençant le principal JavaFX fil au niveau d'un autre thread". Mais dans ce cas, comment puis-je changer la JavaFX des éléments d'interface de la forme et du contenu de façon dynamique, si je ne peux pas (tbh avec plus de précision dire sera "je ne sais pas comment") lier ensemble, quelques fils?

Mise à JOUR : 2014/08/07, 03:42

Après avoir lu donné les réponses, j'ai essayé de mettre en œuvre étant donné les solutions dans le code, afin d'afficher 10 personnalisée Circles sur des endroits différents avec des intervalles de temps entre chaque affichage:

/* in ClassApplication body */
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.setWidth(300);
stage.setHeight(300);
stage.show();
Timeline timeline = new Timeline();
for (int i = 0; i < 10; i++) {
Random r = new Random();
int random = r.nextInt(200) + 25;
KeyFrame f = new KeyFrame(Duration.millis((i + 1) * 1000), 
new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent ae) {
pane.getChildren().add(new Circle(
random, random, 10, Color.RED));
}
});
timeline.getKeyFrames().add(f);
}
timeline.setCycleCount(1);
timeline.play();
}

La solution ci-dessus fonctionne très bien. Je vous remercie beaucoup.

OriginalL'auteur bluevoxel | 2014-08-06