Quiero cargar hasta nueve paneles en un TilePane. Para cada panel tengo que ejecutar primero un cálculo del contenido (aproximadamente 300 ms) y el segundo para construir el Panel (aproximadamente 500 ms). Lo que quiero es que haya nueve ProgressIndicators que intercambien con cada panel después de su cálculo. Lo intenté con el comando Platform.runlater, así como con una clase de servicio. El resultado fue siempre el mismo. ProgressIndicator se muestra, pero no está animado. Después de segundos, hay todos los paneles a la vez. ¿Existe la posibilidad de que los indicadores estén animados en el tiempo del agujero y de que pueda intercambiarlos uno tras otro?Ejecutar tarea en segundo plano en JavaFX
9
A
Respuesta
11
JavaFX tiene Event Dispatch Thread que usa para eventos de UI. Todo el trabajo con UI debería ocurrir en este hilo. Y los cálculos que no sean de IU no deberían ocurrir allí para evitar retrasos en la IU.
Ver siguiente código:
public class Indicators extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
Pane root = new HBox();
stage.setScene(new Scene(root, 300, 100));
for (int i = 0; i < 10; i++) {
final ProgressIndicator pi = new ProgressIndicator(0);
root.getChildren().add(pi);
// separate non-FX thread
new Thread() {
// runnable for that thread
public void run() {
for (int i = 0; i < 20; i++) {
try {
// imitating work
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException ex) {
ex.printStackTrace();
}
final double progress = i*0.05;
// update ProgressIndicator on FX thread
Platform.runLater(new Runnable() {
public void run() {
pi.setProgress(progress);
}
});
}
}
}.start();
}
stage.show();
}
}
12
Así es como he resuelto el problema:
import java.util.Random;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.concurrent.Worker.State;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.TilePane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class Minimal extends Application {
private TilePane loadPane;
private ProgressIndicator[] indicators = new ProgressIndicator[9];
private Label loading[] = new Label[9];
private Color[] colors = {Color.BLACK,Color.BLUE,Color.CRIMSON,Color.DARKCYAN,Color.FORESTGREEN,Color.GOLD,Color.HOTPINK,Color.INDIGO,Color.KHAKI};
private int counter = 0;
@Override
public void start(Stage primaryStage) throws Exception {
//creating Layout
final Group root = new Group();
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.setResizable(false);
StackPane waitingPane = new StackPane();
final ProgressBar progress = new ProgressBar();
Label load = new Label("loading things...");
progress.setTranslateY(-25);
load.setTranslateY(25);
waitingPane.getChildren().addAll(new Rectangle(400,400,Color.WHITE),load,progress);
root.getChildren().add(waitingPane);
//Task for computing the Panels:
Task<Void> task = new Task<Void>() {
@Override
protected Void call() throws Exception {
for (int i = 0; i < 20; i++) {
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException ex) {
ex.printStackTrace();
}
final double prog = i*0.05;
Platform.runLater(new Runnable() {
public void run() {
progress.setProgress(prog);
}
});
}
return null;
}
};
//stateProperty for Task:
task.stateProperty().addListener(new ChangeListener<Worker.State>() {
@Override
public void changed(ObservableValue<? extends State> observable,
State oldValue, Worker.State newState) {
if(newState==Worker.State.SUCCEEDED){
loadPanels(root);
}
}
});
//start Task
new Thread(task).start();
primaryStage.show();
}
private void loadPanels(Group root) {
//change to loadPanel:
root.getChildren().set(0,createLoadPane());
//Service:
final Service<Rectangle> RecBuilder = new Service<Rectangle>() {
@Override protected Task<Rectangle> createTask() {
return new Task<Rectangle>() {
@Override protected Rectangle call() throws InterruptedException {
updateMessage("loading rectangle . . .");
updateProgress(0, 10);
for (int i = 0; i < 10; i++) {
Thread.sleep(100);
}
updateMessage("Finish!");
return new Rectangle((380)/3,(380)/3,colors[counter]);
}
};
}
};
//StateListener
RecBuilder.stateProperty().addListener(new ChangeListener<Worker.State>() {
@Override public void changed(ObservableValue<? extends Worker.State> observableValue,
Worker.State oldState, Worker.State newState) {
switch (newState) {
case SCHEDULED:
break;
case READY:
case RUNNING:
break;
case SUCCEEDED:
Rectangle rec = RecBuilder.valueProperty().getValue();
indicators[counter].progressProperty().unbind();
loading[counter].textProperty().unbind();
loadPane.getChildren().set(counter, rec);
if(counter<8){
counter++;
nextPane(RecBuilder);
}
break;
case CANCELLED:
case FAILED:
loading[counter].textProperty().unbind();
loading[counter].setText("Failed!");
if(counter<8){
counter++;
nextPane(RecBuilder);
}
break;
}
}
});
//begin PanelBuilding:
nextPane(RecBuilder);
}
private void nextPane(Service<Rectangle> recBuilder) {
loading[counter].textProperty().bind(recBuilder.messageProperty());
indicators[counter].visibleProperty().bind(recBuilder.progressProperty().isNotEqualTo(new SimpleDoubleProperty(ProgressBar.INDETERMINATE_PROGRESS)));
recBuilder.restart();
}
private Node createLoadPane() {
loadPane = new TilePane(5,5);
loadPane.setPrefColumns(3);
loadPane.setPadding(new Insets(5));
for(int i=0;i<9;i++){
StackPane waitingPane = new StackPane();
Rectangle background = new Rectangle((380)/3, (380)/3, Color.WHITE);
indicators[i] = new ProgressIndicator();
indicators[i].setPrefSize(50, 50);
indicators[i].setMaxSize(50, 50);
indicators[i].setTranslateY(-25);
indicators[i].setTranslateX(-10);
loading[i] = new Label();
loading[i].setTranslateY(25);
waitingPane.getChildren().addAll(background,indicators[i],loading[i]);
loadPane.getChildren().add(waitingPane);
}
return loadPane;
}
public static void main(String[] args) {
launch(args);
}
}
+0
Gracias. Creo que el problema es que una tarea (mejor una única instancia de tarea) no se puede ejecutar varias veces. Colocando la instancia de la tarea en un método que vamos a reinicializar por cada método, la solucioné para mí también. Agradable :) –
Cuestiones relacionadas
- 1. Cómo programar una tarea en segundo plano
- 2. ejecutar archivo bat en segundo plano
- 3. php ejecutar un proceso en segundo plano
- 4. Git enganche post-commit como tarea en segundo plano
- 5. Evitar que se ejecute la tarea en segundo plano dispatch_after()
- 6. android: ejecutando una tarea en segundo plano usando AlarmManager
- 7. Depurando tareas en segundo plano
- 8. cómo ejecutar mi aplicación en segundo plano en iphone?
- 9. Cómo ejecutar actividad en segundo plano en Android
- 10. Ejecutar escucha de GPS en segundo plano en Android
- 11. cómo ejecutar la aplicación en segundo plano en android?
- 12. Ruby on Rails: ¿Cómo ejecutar cosas en segundo plano?
- 13. ¿Cómo ejecutar programas de Python en segundo plano?
- 14. ¿Cómo ejecutar gdb contra un daemon en segundo plano?
- 15. ¿Cómo ejecutar una secuencia de comandos python en segundo plano?
- 16. ¿Cómo ejecutar siempre un servicio en segundo plano?
- 17. nohup: ejecutar el proceso de PHP en segundo plano
- 18. ¿Cómo ejecutar una aplicación de Android en segundo plano?
- 19. ¿Cómo iniciar y ejecutar un script externo en segundo plano?
- 20. Cómo ejecutar una aplicación de consola .NET en segundo plano
- 21. Android - Ejecutar en segundo plano - Servicio vs. clase Java estándar
- 22. ¿Es posible ejecutar el acelerómetro del iPhone en segundo plano?
- 23. ¿Cómo se obtiene Cloud9 IDE para ejecutar en segundo plano?
- 24. iOS procesado en segundo plano
- 25. Trabajo en segundo plano en Powershell
- 26. ejecutar varios trabajos en segundo plano al mismo tiempo (en paralelo) en r
- 27. Cómo iniciar una tarea en segundo plano en el servicio Android
- 28. Programe una tarea de aplicación iOS para ejecutarla en segundo plano
- 29. Ejecución de múltiples trabajos paralelos en segundo plano con Rails
- 30. Enviar una tarea en segundo plano desde la aplicación mvc de primavera
Hola Sergey ... Tengo una pregunta, que puede tener varios de estos subprocesos que se ejecutan en la aplicación ? Gracias. –
@MarcoR, seguro, puedes ejecutar 'new Thread()' varias veces. –
Gracias Sergey, es recomendable tener varios Platform.runLater en la aplicación ??. Dado que estos hilos tienen que cambiar la vista, para ver si mostrar un cuadro de diálogo. –