I'm trying to simulate a basic thermostat in an application GUI.
我正在尝试在应用程序GUI中模拟基本恒温器。
I want to update a label box value every 2 secs with the new temperature value.
我想用新的温度值每2秒更新一个标签盒值。
For example, my intial temperature will be displayed as 68 degrees and updated to 69, to 70, etc. till 75 every 2 seconds.
例如,我的初始温度将显示为68度并更新为69,至70等,直到每2秒75次。
This is a piece of code I wrote in Java fx. controlpanel
is object of te form where the label box is present. It updates only the final value as 75. It doesnt update it every 2 secs. I have written a method pause to cause a 2 secs delay. All labels are updated with their final values but not updated every 2 secs. When I debug, I can see that the values are increased by one every 2 secs. This code is written in button onClick event
这是我用Java fx编写的一段代码。 controlpanel是te形式的对象,其中存在标签盒。它仅将最终值更新为75.它不会每2秒更新一次。我写了一个方法暂停导致2秒的延迟。所有标签都会更新其最终值,但不会每2秒更新一次。当我调试时,我可以看到值每2秒增加一个。此代码是在按钮onClick事件中编写的
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();
}
}
3 个解决方案
#1
12
To solve your task using Timer you need to implement TimerTask
with your code and use Timer#scheduleAtFixedRate
method to run that code repeatedly:
要使用Timer解决您的任务,您需要使用代码实现TimerTask并使用Timer#scheduleAtFixedRate方法重复运行该代码:
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.print("I would be called every 2 seconds");
}
}, 0, 2000);
Also note that calling any UI operations must be done on Swing UI thread (or FX UI thread if you are using JavaFX):
另请注意,调用任何UI操作必须在Swing UI线程(或FX UI线程,如果您使用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);
}
In case of JavaFX you need to update FX controls on "FX UI thread" instead of Swing one. To achieve that use javafx.application.Platform#runLater
method instead of SwingUtilities
对于JavaFX,您需要更新“FX UI线程”而不是Swing 1的FX控件。要实现这一点,请使用javafx.application.Platform#runLater方法而不是SwingUtilities
#2
8
Here is an alternate solution which uses a JavaFX animation Timeline instead of a Timer.
这是一个替代解决方案,它使用JavaFX动画时间轴而不是Timer。
I like this solution because the animation framework ensures that everything happens on the JavaFX application thread, so you don't need to worry about threading issues.
我喜欢这个解决方案,因为动画框架确保JavaFX应用程序线程上发生了所有事情,因此您不必担心线程问题。
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<ActionEvent>() {
@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);
}
}
The solution is based upon the countdown timer solution from: JavaFX: How to bind two values?
该解决方案基于以下的倒数计时器解决方案:JavaFX:如何绑定两个值?
#3
0
Calling Platform.runLater
worked for me:
调用Platform.runLater为我工作:
Platform.runLater(new Runnable() {
@Override
public void run() {
}
});
#1
12
To solve your task using Timer you need to implement TimerTask
with your code and use Timer#scheduleAtFixedRate
method to run that code repeatedly:
要使用Timer解决您的任务,您需要使用代码实现TimerTask并使用Timer#scheduleAtFixedRate方法重复运行该代码:
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.print("I would be called every 2 seconds");
}
}, 0, 2000);
Also note that calling any UI operations must be done on Swing UI thread (or FX UI thread if you are using JavaFX):
另请注意,调用任何UI操作必须在Swing UI线程(或FX UI线程,如果您使用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);
}
In case of JavaFX you need to update FX controls on "FX UI thread" instead of Swing one. To achieve that use javafx.application.Platform#runLater
method instead of SwingUtilities
对于JavaFX,您需要更新“FX UI线程”而不是Swing 1的FX控件。要实现这一点,请使用javafx.application.Platform#runLater方法而不是SwingUtilities
#2
8
Here is an alternate solution which uses a JavaFX animation Timeline instead of a Timer.
这是一个替代解决方案,它使用JavaFX动画时间轴而不是Timer。
I like this solution because the animation framework ensures that everything happens on the JavaFX application thread, so you don't need to worry about threading issues.
我喜欢这个解决方案,因为动画框架确保JavaFX应用程序线程上发生了所有事情,因此您不必担心线程问题。
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<ActionEvent>() {
@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);
}
}
The solution is based upon the countdown timer solution from: JavaFX: How to bind two values?
该解决方案基于以下的倒数计时器解决方案:JavaFX:如何绑定两个值?
#3
0
Calling Platform.runLater
worked for me:
调用Platform.runLater为我工作:
Platform.runLater(new Runnable() {
@Override
public void run() {
}
});