java - 如何在java fx中每2秒更新一次标签框?

Posted

技术标签:

【中文标题】java - 如何在java fx中每2秒更新一次标签框?【英文标题】:How to update the label box every 2 seconds in java fx? 【发布时间】:2013-04-14 06:02:45 【问题描述】:

我正在尝试在应用程序 GUI 中模拟基本恒温器。

我想用新的温度值每 2 秒更新一次标签框值。

例如,我的初始温度将显示为 68 度,然后每 2 秒更新到 69、70 等,直到 75。

这是我用 Java fx 编写的一段代码。 controlpanel 是标签框所在的表单对象。它仅将最终值更新为 75。它不会每 2 秒更新一次。我写了一个方法 pause 导致 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();
    
   

【问题讨论】:

这与swing 有什么关系? JavaFX 和 Swing 是不同的 GUI 工具包。您通常会使用其中一种。 认为swing框架中是否有解决此问题的方法将帮助我在javafx中实现它 在 Swing 中你会使用 javax.swing.Timer @user1364861 it updates only at last,在这种情况下没有任何帮助,这是原因发布SSCCE,简短,可运行,可编译,否则这个问题根本无法回答 我的计时器没有问题 - 显然你确实对计时器有问题,不知道如何使用它;-) 阅读 api 文档 ...(提示:你的计时器什么都不做) 【参考方案1】:

要使用 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);

另请注意,调用任何 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);

如果是 JavaFX,您需要在“FX UI 线程”而不是 Swing 上更新 FX 控件。要实现这一点,请使用 javafx.application.Platform#runLater 方法而不是 SwingUtilities

【讨论】:

嗨,你知道如何停止这个计时器吗?【参考方案2】:

这是一个替代解决方案,它使用 JavaFX 动画时间轴而不是计时器。

我喜欢这个解决方案,因为动画框架确保一切都发生在 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);
  

该解决方案基于来自:JavaFX: How to bind two values? 的倒数计时器解决方案

【讨论】:

使用动画计时器怎么样?这是否也在 javafx 应用程序线程上运行? 是的,动画计时器确实在 JavaFX 应用程序上运行,是的,它可以以回答这个问题的方式使用。使用时间线更直接,因为它是一个更高级别的结构,它完全满足了问题的要求,每 2 秒调用一次 UI 更新,这种方式对时间线使用的 KeyFrame 结构设置很直观。如果你想做一个更新的时间间隔可能不断变化的游戏循环或物理模型,AnimationTimer 是合适的。 感谢您的解释,是的,我刚试过Timeline,它比AnimationTimer更容易使用【参考方案3】:

致电Platform.runLater 为我工作:

Platform.runLater(new Runnable() 

    @Override
    public void run() 

    
);

【讨论】:

以上是关于java - 如何在java fx中每2秒更新一次标签框?的主要内容,如果未能解决你的问题,请参考以下文章

如何在ios中每n秒获取一次位置更新

如何在android中的ble中每5秒更新一次电池电量

如何在 MVC 4 中每 3 秒刷新一次局部视图?

在 Java FX 工作线程中不断更新 UI

如何在 Python 中每 60 秒异步执行一次函数?

在Swift 2.0中每隔n分钟更新一次背景中的位置