Ricerca…


Aggiornamento dell'interfaccia utente mediante Platform.runLater

Le operazioni a esecuzione prolungata non devono essere eseguite sul thread dell'applicazione JavaFX, poiché ciò impedisce a JavaFX di aggiornare l'interfaccia utente, determinando un'interfaccia utente bloccata.

Inoltre, qualsiasi modifica a un Node che fa parte di un grafico di scena "live" deve avvenire nel thread dell'applicazione JavaFX. Platform.runLater può essere utilizzato per eseguire tali aggiornamenti sul thread dell'applicazione JavaFX.

Nell'esempio seguente viene illustrato come aggiornare ripetutamente un Node Text da un thread diverso:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class CounterApp extends Application {

    private int count = 0;
    private final Text text = new Text(Integer.toString(count));

    private void incrementCount() {
        count++;
        text.setText(Integer.toString(count));
    }

    @Override
    public void start(Stage primaryStage) {
        StackPane root = new StackPane();
        root.getChildren().add(text);

        Scene scene = new Scene(root, 200, 200);

        // longrunning operation runs on different thread
        Thread thread = new Thread(new Runnable() {

            @Override
            public void run() {
                Runnable updater = new Runnable() {

                    @Override
                    public void run() {
                        incrementCount();
                    }
                };

                while (true) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ex) {
                    }

                    // UI update is run on the Application thread
                    Platform.runLater(updater);
                }
            }

        });
        // don't let thread prevent JVM shutdown
        thread.setDaemon(true);
        thread.start();

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

}

Raggruppamento degli aggiornamenti dell'interfaccia utente

Il seguente codice rende l'interfaccia utente non risponde per un breve periodo dopo il clic del pulsante, poiché vengono utilizzate troppe chiamate Platform.runLater . (Prova a scorrere il ListView immediatamente dopo il clic del pulsante.)

@Override
public void start(Stage primaryStage) {
    ObservableList<Integer> data = FXCollections.observableArrayList();
    ListView<Integer> listView = new ListView<>(data);
    
    Button btn = new Button("Say 'Hello World'");
    btn.setOnAction((ActionEvent event) -> {
        new Thread(() -> {
            for (int i = 0; i < 100000; i++) {
                final int index = i;
                Platform.runLater(() -> data.add(index));
            }
        }).start();
    });

    Scene scene = new Scene(new VBox(listView, btn));

    primaryStage.setScene(scene);
    primaryStage.show();
}

Per evitare ciò invece di utilizzare un numero elevato di aggiornamenti, il seguente codice utilizza un AnimationTimer per eseguire l'aggiornamento solo una volta per frame:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.animation.AnimationTimer;

public class Updater {

    @FunctionalInterface
    public static interface UpdateTask {

        public void update() throws Exception;
    }

    private final List<UpdateTask> updates = new ArrayList<>();

    private final AnimationTimer timer = new AnimationTimer() {

        @Override
        public void handle(long now) {
            synchronized (updates) {
                for (UpdateTask r : updates) {
                    try {
                        r.update();
                    } catch (Exception ex) {
                        Logger.getLogger(Updater.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
                updates.clear();
                stop();
            }
        }
    };

    public void addTask(UpdateTask... tasks) {
        synchronized (updates) {
            updates.addAll(Arrays.asList(tasks));
            timer.start();
        }
    }

}

che consente di raggruppare gli aggiornamenti utilizzando la classe Updater :

private final Updater updater = new Updater();

...

        // Platform.runLater(() -> data.add(index));
        updater.addTask(() -> data.add(index));

Come utilizzare il servizio JavaFX

Invece di eseguire attività intensive in JavaFX Thread che dovrebbero essere eseguite in un Service . Quindi, in pratica, cos'è un servizio ?

Un servizio è una classe che sta creando un nuovo Thread ogni volta che si avvia esso ed è passato un task ad esso per fare un po 'Servizio work.The può restituire o meno un valore.

Di seguito è riportato un tipico esempio di servizio JavaFX che sta facendo un po 'di lavoro e restituisce una Map<String,String>( ):

public class WorkerService extends Service<Map<String, String>> {

    /**
     * Constructor
     */
    public WorkerService () {

        // if succeeded
        setOnSucceeded(s -> {
            //code if Service succeeds
        });

        // if failed
        setOnFailed(fail -> {
            //code it Service fails
        });

        //if cancelled
        setOnCancelled(cancelled->{
            //code if Service get's cancelled
        });
    }

    /**
    * This method starts the Service
    */
    public void startTheService(){
        if(!isRunning()){
           //...
           reset();
           start();
        }

    }

    @Override
    protected Task<Map<String, String>> createTask() {
        return new Task<Map<String, String>>() {
            @Override
            protected Void call() throws Exception {

                    //create a Map<String, String>
                    Map<String,String> map  = new HashMap<>();

                   //create other variables here

                   try{
                        //some code here
                        //.....do your manipulation here

                        updateProgress(++currentProgress, totalProgress);
                    }

                } catch (Exception ex) {                  
                    return null; //something bad happened so you have to do something instead of returning null
                }

                return map;
            }
        };
    }

}


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow