I have a sample Hello World JavaFx. I am using Eclipse and eFxclipse plugin. My Eclipse is kepler which is Eclipse 4.3.2 version and Java servion is Jdk1.7-045.
Wh
This answer specially talks about the use of Platform.runLater. If you are using Task, you are better off updating the UI using the method it provides as stated in kleopatra's answer.
For updating the UI, you have to be on the Javafx thread.
Once you are on any other thread, use Platform.runLater() to update those data back to Javafx UI. A working example can be found below
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class HelloWorld extends Application {
private static final short COREPOOLSIZE = 2;
private static final short MAXIMUMPOOLSIZE = 2;
private static final int WORKQUEUECAPACITY = 100;
private ExecutorService executors = new
ThreadPoolExecutor(COREPOOLSIZE, MAXIMUMPOOLSIZE, 20, TimeUnit.MINUTES,
new ArrayBlockingQueue<Runnable>(WORKQUEUECAPACITY));
public static void main(String[] args) {
launch(args);
}
@Override
public void start(final Stage primaryStage) throws InterruptedException {
primaryStage.setTitle("Hello World!");
final Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
final StackPane root = new StackPane();
root.getChildren().add(btn);
final Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
Task<Boolean> task = new Task<Boolean>() {
@Override
public Boolean call() {
final AtomicInteger i = new AtomicInteger(0);
for( ; i.get() < 20; i.incrementAndGet()) {
Platform.runLater(new Runnable() {
@Override
public void run() {
btn.setText("First row\nSecond row " + i);
}
});
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {}
}
return Boolean.valueOf(true);
}
};
executors.submit(task);
}
}
For more information you can go through the links provided here
A Task is designed to interact with the ui on the fx-application thread, to take advantage of that support you should use it as designed :-)
As a general rule, you must not access ui in the call method [*] of the Task. Instead, update one of its properties (message, progress ...) and bind that property to your ui. Sample code:
Task<Boolean> taskWithBinding = new Task<Boolean>() {
@Override
public Boolean call() {
final AtomicInteger i = new AtomicInteger(0);
for( ; i.get() < 20; i.incrementAndGet()) {
updateMessage("First row\nSecond row " + i);
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
return Boolean.FALSE;
}
}
return Boolean.TRUE;
}
};
btn.textProperty().bind(taskWithBinding.messageProperty());
[*] The one exception is outlined (wrap the access into an runLater) in the other answer. Doing so is technically correct - but then you are by-passing a Task's abilities and could use an arbitrary Runnable ...