javafx, aggiorna ui da un altro thread

Ho un’applicazione javafx e un thread di lavoro, implementato tramite javafx.concurrent.Task , che esegue un processo lungo, che sta comprimendo e caricando un insieme di file.
Ho collegato l’avanzamento dell’attività a una barra di progressProperty tramite progressProperty .
Oltre a questo voglio uno stato dettagliato sull’object in elaborazione da riportare nell’interfaccia utente. Cioè, il nome del file che viene elaborato insieme alle sue dimensioni e qualsiasi errore che possa sorgere dal processo di singolo file.
L’aggiornamento dell’interfaccia utente con queste informazioni non può essere eseguito dal thread di lavoro, al massimo posso aggiungerlo a una raccolta sincronizzata.
Ma poi ho bisogno di qualche evento per informare l’interfaccia utente che sono disponibili nuovi dati.
Javafx ha qualche supporto specifico per questo problema?

aggiornamento, formulazione migliore

Invece di progettare un meccanismo cross-thread ad hoc come Platform.runLater, sto provando a consentire a ogni proprietà di essere ascoltata da altri thread. Proprio come eseguireProperty e stateProperty fornite da Task

Mi sto imbattendo in un problema simile, per quanto posso dire che devi gestire l’errore gestendo te stesso. La mia soluzione è aggiornare l’interfaccia utente tramite una chiamata al metodo:

Qualcosa di simile a:

  try { //blah... } catch (Exception e) { reportAndLogException(e); } ... public void reportAndLogException(final Throwable t) { Platform.runLater(new Runnable() { @Override public void run() { //Update UI here } }); } 

In sostanza sto semplicemente spostandolo manualmente sul thread UI per un aggiornamento (come farei praticamente in qualsiasi altro framework).

Questa risposta usa lo stesso concetto della risposta di Daniel.

In allegato c’è una copia dell’esempio di Risultato parziale dal javadoc Task (corretto per gli errori di syntax attualmente incorporati nel javadoc di Java 8 e per aggiungere tipi generici più specifici). Puoi usare una modifica di questo.

Inserire le eccezioni nella raccolta partialResults. Per il tuo caso, non è necessario restituire l’elenco di eccezioni dall’attività, ma possono invece inserirli in un controllo dell’interfaccia utente che visualizza le eccezioni (come un ListView con un object CellFactory per la visualizzazione delle eccezioni). Si noti che la raccolta partialResults non ha bisogno di essere sincronizzata perché è sempre aggiornata e accede al thread UI JavaFX (l’aggiornamento avviene tramite una chiamata Platform.runLater() simile alla soluzione di Daniel).

 public class PartialResultsTask extends Task> { private ReadOnlyObjectWrapper> partialResults = new ReadOnlyObjectWrapper<>( this, "partialResults", FXCollections.observableArrayList( new ArrayList<>() ) ); public final ObservableList getPartialResults() { return partialResults.get(); } public final ReadOnlyObjectProperty> partialResultsProperty() { return partialResults.getReadOnlyProperty(); } @Override protected ObservableList call() throws Exception { updateMessage("Creating Rectangles..."); for (int i = 0; i < 100; i++) { if (isCancelled()) break; final Rectangle r = new Rectangle(10, 10); r.setX(10 * i); Platform.runLater(() -> partialResults.get().add(r)); updateProgress(i, 100); } return partialResults.get(); } } 

Quando si aggiornano le sue proprietà osservabili L’attività verifica innanzitutto se l’aggiornamento si sta verificando sul thread dell’applicazione FX. Se lo è, fa un aggiornamento immediato. In caso contrario, avvolge l’aggiornamento in una chiamata Platform.runLater() . Vedi il codice sorgente dell’attività per capire come è fatto.

Forse sarebbe ansible definire un insieme di proprietà generiche concomitanti, ma JavaFX non fornisce tali funzionalità al suo nucleo. In effetti, non è necessario. Ad eccezione del pacchetto javafx.concurrent, JavaFX è un framework UI a thread singolo.