¿Cómo actualizar el cuadro de etiqueta cada 2 segundos en java fx?

Intento simular un termostato básico en una GUI de la aplicación.

Quiero actualizar un valor de cuadro de etiqueta cada 2 segundos con el nuevo valor de temperatura.

Por ejemplo, mi temperatura inicial se mostrará como 68 grados y se actualizará a 69, a 70, etc. hasta 75 cada 2 segundos.

Esta es una pieza de código que escribí en Java fx. controlpanel es el objeto de la forma donde está presente la etiqueta. Actualiza solo el valor final como 75. No lo actualiza cada 2 segundos. He escrito una pausa de método para causar un retraso de 2 segundos. Todas las tags se actualizan con sus valores finales pero no se actualizan cada 2 segundos. Cuando depuro, puedo ver que los valores se incrementan en uno cada 2 segundos. Este código está escrito en el botón en evento Click

 private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) { int i=0; Timer asd = new Timer(1000,null); asd.setDelay(1000); while(i < 10) { jTextField1.setText(Integer.toString(i)); i++; asd.start(); } } 

Para resolver su tarea usando Timer, necesita implementar TimerTask con su código y usar Timer#scheduleAtFixedRate método Timer#scheduleAtFixedRate para ejecutar ese código repetidamente:

 Timer timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { System.out.print("I would be called every 2 seconds"); } }, 0, 2000); 

También tenga en cuenta que llamar a cualquier operación de UI se debe hacer en el subproceso de la interfaz de usuario Swing (o en el subproceso de interfaz de usuario FX si está usando JavaFX):

 private int i = 0; private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) { Timer timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { jTextField1.setText(Integer.toString(i++)); } }); } }, 0, 2000); } 

En el caso de JavaFX, necesita actualizar los controles de efectos en “subproceso de interfaz de usuario FX” en lugar de cambiar uno. Para lograr eso, use javafx.application.Platform#runLater método javafx.application.Platform#runLater lugar de SwingUtilities

Aquí hay una solución alternativa que utiliza una línea de tiempo de animación JavaFX en lugar de un temporizador.

Me gusta esta solución porque el marco de animación garantiza que todo suceda en el hilo de la aplicación JavaFX, por lo que no tendrá que preocuparse por problemas de subprocesamiento.

probeta de temperatura

 import javafx.animation.*; import javafx.application.Application; import javafx.beans.binding.Bindings; import javafx.beans.property.*; import javafx.event.*; import javafx.scene.*; import javafx.scene.control.*; import javafx.scene.layout.VBox; import javafx.stage.Stage; import javafx.util.Duration; import java.util.Random; public class ThermostatApp extends Application { @Override public void start(final Stage stage) throws Exception { final Thermostat thermostat = new Thermostat(); final TemperatureLabel temperatureLabel = new TemperatureLabel(thermostat); VBox layout = new VBox(10); layout.getChildren().addAll(temperatureLabel); 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 TemperatureLabel extends Label { public TemperatureLabel(final Thermostat thermostat) { textProperty().bind( Bindings.format( "%3d \u00B0F", thermostat.temperatureProperty() ) ); } } class Thermostat { private static final Duration PROBE_FREQUENCY = Duration.seconds(2); private final ReadOnlyIntegerWrapper temperature; private final TemperatureProbe probe; private final Timeline timeline; public ReadOnlyIntegerProperty temperatureProperty() { return temperature.getReadOnlyProperty(); } public Thermostat() { probe = new TemperatureProbe(); temperature = new ReadOnlyIntegerWrapper(probe.readTemperature()); timeline = new Timeline( new KeyFrame( Duration.ZERO, new EventHandler() { @Override public void handle(ActionEvent actionEvent) { temperature.set(probe.readTemperature()); } } ), new KeyFrame( PROBE_FREQUENCY ) ); timeline.setCycleCount(Timeline.INDEFINITE); timeline.play(); } } class TemperatureProbe { private static final Random random = new Random(); public int readTemperature() { return 72 + random.nextInt(6); } } 

La solución se basa en la solución del temporizador de cuenta regresiva de: JavaFX: ¿Cómo vincular dos valores?

Llamar a Platform.runLater funcionó para mí:

 Platform.runLater(new Runnable() { @Override public void run() { } });