Suche…


Aktualisieren der Benutzeroberfläche mit Platform.runLater

Langfristige Vorgänge dürfen nicht auf dem JavaFX-Anwendungsthread ausgeführt werden, da JavaFX die Benutzeroberfläche nicht aktualisieren kann, was zu einer eingefrorenen Benutzeroberfläche führt.

Darüber hinaus muss jede Änderung an einem Node , der Teil eines "Live" -Szenendiagramms ist , im JavaFX-Anwendungsthread vorgenommen werden. Platform.runLater kann verwendet werden, um diese Aktualisierungen im JavaFX-Anwendungsthread auszuführen.

Das folgende Beispiel zeigt , wie ein aktualisieren Text Node wiederholt von einem anderen Thread:

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);
    }

}

Aktualisieren der Benutzeroberfläche

Mit dem folgenden Code reagiert die Benutzeroberfläche nach dem Klicken der Schaltfläche kurze Zeit nicht, da zu viele Aufrufe von Platform.runLater verwendet werden. (Scrollen Sie die ListView sofort nach dem Klicken der Schaltfläche.)

@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();
}

Um dies zu verhindern, anstatt eine große Anzahl von Updates zu verwenden, verwendet der folgende Code einen AnimationTimer , um das Update nur einmal pro Frame auszuführen:

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();
        }
    }

}

Dadurch können die Updates mit der Updater Klasse gruppiert werden:

private final Updater updater = new Updater();

...

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

So verwenden Sie den JavaFX-Service

Anstatt intensive Aufgaben in JavaFX Thread auszuführen, sollte dies in einem Service ausgeführt werden. Was ist im Grunde ein Dienst ?

Ein Service ist eine Klasse, die bei jedem Start einen neuen Thread und eine Aufgabe an sie weitergibt, um Arbeiten auszuführen. Der Service kann einen Wert zurückgeben oder nicht.

Im Folgenden finden Sie ein typisches Beispiel für den JavaFX-Service, der einige Arbeit leistet und Map<String,String>( ) 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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow