Newsgroup: it.comp.java
Titolo: Era: aggiornamento real-time di controlli in applicazione JavaFX

(pre scriptum... avevo giï¿œ postato questo ma non vedendolo forse ï¿œ 
andato perso... nel caso ï¿œ un mio problema, mi scuso, p.s. se avete giï¿œ 
risposto ï¿œ possibile che io non veda nemmeno la vostra risposta, grazie).
 
Il programma seguente, apre una finestra con un TextField e un bottone,
premendo il bottone parte un conteggio da zero a nMax.
 
Non riesco a vedere la scritta Numero i (o k) per ogni numero, ma vedo 
soltanto l'ultimo...
Ho provato sia con Platform.runLater che senza ma non c'ï¿œ verso... il 
controllo (TextField) verrï¿œ
aggiornato sulla finestra soltanto alla fine del ciclo.
E' possibile fare in modo che ad ogni modifica di un controllo, esso 
venga ridisegnato?
Oppure anche un "redraw" dell'intera scena...
Grazie per l'aiuto...
 
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TestFX extends Application {
     final static int nMax = 1000000;
     @Override
     public void start(Stage primaryStage) {
         TextField myTextField = new TextField();
         Button btn = new Button("click me");
         btn.setOnMouseClicked((MouseEvent me) -> {
             for(int i=0;i<nMax;++i) {
                 if(Platform.isFxApplicationThread()) {
                     myTextField.setText("Numero " + i);
                 } else {
                     final int k = i;
                     Platform.runLater(()->myTextField.setText("Numero " 
+ k));
                 }
             }
             myTextField.setText("Finito ( "+ nMax +")");
         });
         VBox vbox = new VBox();
         vbox.getChildren().addAll(myTextField,btn);
         Scene scene = new Scene(vbox);
         primaryStage.setTitle("Hello World!");
         primaryStage.setScene(scene);
         primaryStage.show();
     }
 
     public static void main(String[] args) {
         launch(args);
     }
}

Ciao, ho esaminato un po' la questione, sembra che l'unica soluzione
senza impazzire a gestire i thread sia l'uso del JavaFX animation framework
per creare e gestire le animazioni. Ecco di seguito un esempio:
 
/*
 * Here is an alternate solution to your countdown binding problem
 * which uses the JavaFX animation framework rather than the
 * concurrency framework. I prefer this because it keeps everything
 * on the JavaFX application thread and you don't need to worry
 * about concurrency issues which are difficult to understand and debug.
 */
import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.*;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*;
import javafx.event.*;
import javafx.geometry.Pos;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
 
public class CountdownTimer extends Application
{
	@Override
	public void start(final Stage stage) throws Exception
	{
		final CountDown      countdown      = new CountDown(10);
		final CountDownLabel countdownLabel = new CountDownLabel(countdown);
 
		final Button countdownButton = new Button("  Start  ");
		countdownButton.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent t) {
				countdownButton.setText("Restart");
				countdown.start();
			}
		});
 
		VBox layout = new VBox(10);
		layout.getChildren().addAll(countdownLabel, countdownButton);
		layout.setAlignment(Pos.BASELINE_RIGHT);
		layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 20;
-fx-font-size: 20;");
 
		stage.setScene(new Scene(layout));
		stage.show();
	}
 
	public static void main(String[] args) throws Exception {
		launch(args);
	}
}
 
class CountDownLabel extends Label {
	public CountDownLabel(final CountDown countdown) {
		textProperty().bind(Bindings.format("%3d", countdown.timeLeftProperty()));
	}
}
 
class CountDown
{
	private final ReadOnlyIntegerWrapper timeLeft;
	private final ReadOnlyDoubleWrapper timeLeftDouble;
	private final Timeline timeline;
 
	public ReadOnlyIntegerProperty timeLeftProperty()
	{
		return timeLeft.getReadOnlyProperty();
	}
 
	public CountDown(final int time)
	{
		timeLeft       = new ReadOnlyIntegerWrapper(time);
		timeLeftDouble = new ReadOnlyDoubleWrapper(time);
 
		timeline = new Timeline(new KeyFrame(Duration.ZERO,
					            new KeyValue(timeLeftDouble, time)),
					            new KeyFrame(Duration.seconds(time),
					            new KeyValue(timeLeftDouble, 0)));
 
		timeLeftDouble.addListener(new InvalidationListener() {
			@Override
			public void invalidated(Observable o) {
				timeLeft.set((int) Math.ceil(timeLeftDouble.get()));
			}
		});
	}
 
	public void start()
	{
		timeline.playFromStart();
	}
}
 
 

 per creare e gestire le animazioni. Ecco di seguito un esempio:
Ti ringrazio moltissimo per aver analizzato la questione... ti assicuro 
che ho usato Google per ore ma non ho trovato soluzione. La tua ï¿œ 
l'unica soluzione che ho.
Molti mi avevano detto di usare runLater ma evidentemente multipli 
accessi che modificano lo stato dei controlli, vengono (giustamente se 
vuoi) bufferizzati. Purtroppo a me serviva (non per questo stupido 
esempio che ho creato per la domanda, ma per un gioco di scacchiera), 
aggiornare delle immagini e... non me lo fa.
Ora mi studierï¿œ il tuo esempio perchï¿œ non sono ancora esperto di Java e 
sto imparando, e cercherï¿œ di capire come funzione...
Caspita... Java ï¿œ soprendente... si fanno cose incredibili con poche 
righe e per aggiornare un controllo si diventa matti...
Grazie tante! Hai fatto anche troppo! :)


 per creare e gestire le animazioni. Ecco di seguito un esempio:
 
OK. Ho esaminato il tuo codice e ti ringrazio. Cosï¿œ funziona!
Per quello che devo fare posso continuare a usare swing che ha il metodo 
update() che fa al caso mio...
Trovo stupido invocare l'artiglieria pesante per un programmino con 
pochi controlli standard. FX andrï¿œ benissimo per cose ben piï¿œ complesse.
 
Peccato perï¿œ, potevano mettere un metodo per forzare l'update anche in 
FX. Poi se ti serviva lo usavi altrimenti, no.
Ciao, grazie e buona giornata!