当前位置: 首页 > 知识库问答 >
问题:

Javafx:如果服务消息更新,标签将变为空白(标签绑定到消息)

岳出野
2023-03-14

我是java和javaFx的新手,我正在尝试处理一个需要在标签上显示一些实时传入数据的项目。

我将我的标签绑定到服务对象的消息,该消息不断使用传入数据更新其消息。但是,消息正在更新,但标签变为空白。

没有弹出错误,也没有捕获到异常。任何人都可以指出标签空白的原因,而不是随服务一起更新。消息以及如何修复它?提前谢谢。

下面是我正在尝试做的一个简化示例,其中数据源被随机数列表替换。

控制器类:我将scheduledservice对象放入其中,并将其绑定到标签。

import javafx.concurrent.ScheduledService;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.util.Duration;

public class Controller {
    @FXML
    Button startButton;

    @FXML
    Label updateLabel;

    @FXML
    void display(ActionEvent event) throws Exception{
        Steaming steaming = new Steaming();

        ScheduledService<Void> service = new ScheduledService<Void>() {
            protected Task<Void> createTask() {
                return new Task<Void>() {
                    protected Void call() {
                        // Call the method and update the message

                        updateMessage(steaming.processData());
                        return null; // Useful in case you want to return data, else null
                    }
                };
            }

        };
        service.setPeriod(Duration.seconds(1)); //Runs every 1 seconds
        service.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent t) {
                System.out.println("Message:" + service.messageProperty());
            }
        });

        updateLabel.textProperty().bind(service.messageProperty());
        service.start();

    }
}

Streaming类包含一个列表,我在其中生成1000个随机整数。processData方法将返回并删除列表中的第一个元素。

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Steaming{

    List<Integer> numbers;

    Steaming()
    {
        numbers = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            numbers.add(i);
        }

        Collections.shuffle(numbers);
    }

    public String processData (){
        String s = "loading";
        try {
            s = this.numbers.get(0).toString();
            numbers.remove(0);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return s;
    }
} 

主课堂,展示初级舞台

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("/sample.fxml"));
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root, 300, 275));
        primaryStage.show();

    }

    public static void main(String[] args) {
        launch(args);
    }
}

FXML文件

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>

<GridPane alignment="center" hgap="10" vgap="10" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
   <columnConstraints>
      <ColumnConstraints />
   </columnConstraints>
   <rowConstraints>
      <RowConstraints />
   </rowConstraints>
   <children>
      <HBox prefHeight="100.0" prefWidth="200.0">
         <children>
            <Button fx:id="startButton" mnemonicParsing="false" onAction="#display" text="Button">
               <HBox.margin>
                  <Insets right="5.0" />
               </HBox.margin>
            </Button>
            <Label fx:id="updateLabel" prefHeight="26.0" prefWidth="105.0" text="loading">
               <HBox.margin>
                  <Insets left="10.0" />
               </HBox.margin></Label>
         </children>
      </HBox>
   </children>
</GridPane>

运行结果:以下是服务启动前和启动后的两张图片。

单击按钮前,标签显示“加载”

单击按钮后,标签不显示任何内容

这是从程序中得到的部分最终结果。

Message:StringProperty [bean: sample.Controller$1@7db1e6b2, name: message, bound, value: 33]
Message:StringProperty [bean: sample.Controller$1@7db1e6b2, name: message, bound, value: 200]
Message:StringProperty [bean: sample.Controller$1@7db1e6b2, name: message, bound, value: 389]
Message:StringProperty [bean: sample.Controller$1@7db1e6b2, name: message, bound, value: 188]
Message:StringProperty [bean: sample.Controller$1@7db1e6b2, name: message, bound, value: 915]
Message:StringProperty [bean: sample.Controller$1@7db1e6b2, name: message, bound, value: 76]
Message:StringProperty [bean: sample.Controller$1@7db1e6b2, name: message, bound, value: 205]
Message:StringProperty [bean: sample.Controller$1@7db1e6b2, name: message, bound, value: 583]
Message:StringProperty [bean: sample.Controller$1@7db1e6b2, name: message, bound, value: 181]
Message:StringProperty [bean: sample.Controller$1@7db1e6b2, name: message, bound, value: 872]

我也是新加入这个社区的,如果我在帖子中做错了什么或违反了这里的任何规则,请也指出。非常感谢!

共有2个答案

葛海阳
2023-03-14

添加到Slaw的答案:

使用JavaFx动画工具是否适合您?

    Steaming steaming = new Steaming();
    Timeline timeline = new Timeline(
            new KeyFrame(Duration.millis(1000),
            t -> updateLabel.setText(steaming.processData()))
        );
     timeline.setCycleCount(Timeline.INDEFINITE);
     timeline.play();

如果<代码>蒸汽。processData()很长,如果要将其保留在后台线程中,可以这样更新gui:

    Steaming steaming = new Steaming();
    ScheduledService<Void> service = new ScheduledService<>() {
        @Override
        protected Task<Void> createTask() {
            return new Task<>() {
                @Override
                protected Void call() {
                    String text = steaming.processData();
                    Platform.runLater(()->  updateLabel.setText(text));
                    return null;
                }
            };
        }
    };
    service.setPeriod(Duration.seconds(1)); //Runs every 1 seconds
    service.start();
严劲
2023-03-14

schduledService成功时,它会为下一个执行周期重新安排自己。此过程的一部分是将一些属性“重置”为其默认值,包括将消息属性设置为"1。所以发生的情况是您的服务成功、重新启动,并且消息设置回"太快了,无法在Label中呈现。

由于您的代码只会更新消息,因此一种解决方案是返回流式处理的结果。改为processData()。然后,您将绑定到ScheduledService的lastValue属性。它必须是lastValue,而不是value,因为后者在重置/重新启动时也会被清除。

ScheduledService<String> service = new ScheduledService<>() {

    @Override
    protected Task<String> createTask() {
        return new Task<>() {

            @Override
            protected String call() throws Exception {
                return streaming.processData();
            }

        };
    }

};

updateLabel.textProperty().bind(service.lastValueProperty());

1。我找不到关于这方面的文档,但找到了服务的实现。reset()显示了这种情况(ScheduledService扩展Service)。即使没有清除属性,启动服务的过程也包括将属性绑定到新创建的且未设置任何属性的基础任务

2。此行为已记录在案

 类似资料:
  • 我在JavaFX应用程序中使用MVP。 资源: 控制器: 看法 在我的InfoStageView中,只需初始化我的标签和样式我的视图。 如何将我的超链接绑定到我的标签。我尝试了一些方法,但没有成功。我的StringProperty不可点击,但很容易绑定。 我的目标:我想打开带有链接的浏览器。

  • 我想在我的应用程序中添加一个时钟,它告诉你已经做了多长时间的任务。为了简化它,我包含了一个计数器,它在新线程中每秒递增一次,并用计数器号更新标签“Set Timer”。为此,我在我的.fxml文件中有一个标签fx:id=“settimer”,并将其导入到我的类中。 我试过很多方法来解决我的问题,但我还没有找到正确的方法。我对我想做什么的想法应该很清楚,如果有人能帮助我,我会很高兴的。我的问题是更新

  • 我想做的是: 我有一个JavaFX窗口,我通过拖动不断改变它的宽度和高度。然后的文本具有以下格式: 例子: 我想使用绑定,而不是使用2(两)个ChangeListeners来实现这一点。 我也读过这个问题JavaFX绑定到多个属性

  • 我正在尝试将我的spring mvc项目转换成spring boot。我转换了所有必要的文件根据spring引导。没有错误在控制台。但是当我在浏览器中运行我的web应用程序时,我会得到这个错误。错误:“白标签错误页”没有可用的消息请告诉我为什么我得到这个错误和如何解决它? pageController.java onlineShoppingApplication.java Dispatcher-s

  • @CategoryValidator由CategoryValidatorImpl验证: 和CategoryController的一部分: 在输入字段中,当我输入一个空白时,验证器使用控制器中的hasErrors正确地发现它,但当我在发现空白并返回false后返回表单时,它会给出以下信息:

  • 我有一个名为的单例。它负责在菜单中显示正确的文本。它会动态更新。 我有一个fxml文件,但是MenuText不能有对它的引用。(这将与MVVM体系结构风格相矛盾) 这是正确的做法吗?我现在有了一个MenuFactory,它也是在JavaFX方法中创建的。它设置场景的父级。 start()mehtod如下所示: 这让它变得更加复杂,我不确定这是否正确。此外,我仍然不知道如何设置fxml文件中的菜单文