JavaFX:如何使用Task将值从后台线程传递到JavaFX UI线程 [英] JavaFX : How to pass value from background thread to JavaFX UI thread with Task

查看:107
本文介绍了JavaFX:如何使用Task将值从后台线程传递到JavaFX UI线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个工作程序任务,该任务连续消耗Web服务并返回整数值.

I have one worker task which continuously consumes web service and returns integer value.

我的应用程序由不同的(30)文本框和相关的单选按钮组成. 当我单击单选按钮时,我想在单选按钮旁边的文本"字段中显示后台任务的值.

My Application consist of different (30) text boxes with associated radio button. When I click radio button, I want to display value from background task into Text field next to radio button.

在这种特殊情况下,如何将值从后台线程传递给JAVAFX UI线程?

How I can Pass value from background thread to JAVAFX UI thread in this particular situation?

我是JavaFX的新手,并按以下方式使用.这是正确的方法吗?

I am new to JavaFX and used following way. Is this correct approach?

@FXML
private TabPane mainTabPane;

在主窗口控制器中创建的任务,并且也在主窗口控制器中运行

Created Task in main window controller and also running in main window controller

myScheduledService.setPeriod(Duration.seconds(10));
myScheduledService.start();

并创建任务:

private class MyScheduledService extends ScheduledService {

    @Override
    protected Task createTask() {
        return  new Task() {
            @Override
            protected String call() throws IOException, ParseException {
        // calling web service here
        Integer data = callToMyWebService();
        Tab tab = mainTabPane.getTabs().get(mainTabPane.getTabs().size() - 1);
        BorderPane pane = (BorderPane) tab.getContent();
                    HBox hBox = ((HBox) pane.getChildren().get(0));
        Text operationValueDisplayText = (Text) hbox.getChildren().get(2);
        // displaying data in text box
        operationValueDisplayText.setText(String.valueOf(data));

        }

}; }

推荐答案

一种解决方案(在下面详细实现)是让UI的控制器公开一个属性,并在控制器内部侦听此属性的更改以进行更新显示器.然后,编排应用程序的组件将控制器的属性绑定到服务的lastValueProperty.

One solution (implemented in detail below) is to have the controller of the UI expose a property and, inside the controller, listen to changes of this property to update the display. Then the component orchestrating the application binds the property of the controller to the lastValueProperty of the service.

提供以下服务:

import javafx.concurrent.ScheduledService;
import javafx.concurrent.Task;

public class BgrdService extends ScheduledService<String> {
    @Override protected Task<String> createTask() {
        return new BgrdTask();
    }
}

...和任务:

import java.util.Date;
import javafx.concurrent.Task;

class BgrdTask extends Task<String> {
    @Override protected String call() throws Exception {
        return new Date().toString();
    }
}

我们创建UI的控制器,其中valueProperty最终将绑定到服务,并且只要服务值或选定的切换更改时,就会调用方法updateUi():

We create the controller of the UI, where the valueProperty will ultimately be bound to the service and the method updateUi() is called whenever the service value or the selected toggle changes:

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.GridPane;

public class MainController {

    @FXML
    private ToggleGroup myToggleGroup;

    @FXML
    private GridPane grid;

    @FXML
    private Label label;

    private StringProperty valueProperty = new SimpleStringProperty("");

    @FXML
    void initialize() {
        valueProperty.addListener((observable, oldValue, newValue) -> {
            updateUi();
        });
        myToggleGroup.selectedToggleProperty().addListener((observable, oldValue, newValue) -> {
            updateUi();
        });
    }

    private void updateUi() {
        String displayValue = getValue();
        label.setText(displayValue);
        int index = myToggleGroup.getToggles().indexOf(myToggleGroup.getSelectedToggle());
        if( index >= 0 ) {
            TextField textField = (TextField) grid.getChildren().get(index);
            textField.setText(displayValue);
        }
    }

    public String getValue() { return valueProperty.get(); }
    public void setValue(String value) { valueProperty.set(value); }
    public StringProperty valueProperty() { return this.valueProperty; }
}

注意:为简单起见,updateUi()的实现非常幼稚,并且基于以下FXML;您可能希望在现实生活中使用更智能的东西:

NOTE: To keep things simple, the implementation of updateUi() is very naive and based on the following FXML; you probably want something smarter in a real-life app:

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

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>

<VBox xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1">
    <fx:define>
        <ToggleGroup fx:id="myToggleGroup"/>
    </fx:define>
    <children>
        <GridPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="600.0" fx:id="grid">
            <columnConstraints>
                <ColumnConstraints hgrow="NEVER" minWidth="10.0" prefWidth="300.0"/>
                <ColumnConstraints halignment="CENTER" hgrow="NEVER" minWidth="40.0"/>
            </columnConstraints>
            <rowConstraints>
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER"/>
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER"/>
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER"/>
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER"/>
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="NEVER"/>
            </rowConstraints>
            <children>
                <TextField/>
                <TextField GridPane.rowIndex="1"/>
                <TextField GridPane.rowIndex="2"/>
                <TextField GridPane.rowIndex="3"/>
                <TextField GridPane.rowIndex="4"/>
                <RadioButton toggleGroup="$myToggleGroup" mnemonicParsing="false" GridPane.columnIndex="1" />
                <RadioButton toggleGroup="$myToggleGroup" mnemonicParsing="false" GridPane.columnIndex="1" GridPane.rowIndex="1" />
                <RadioButton toggleGroup="$myToggleGroup" mnemonicParsing="false" GridPane.columnIndex="1" GridPane.rowIndex="2" />
                <RadioButton toggleGroup="$myToggleGroup" mnemonicParsing="false" GridPane.columnIndex="1" GridPane.rowIndex="3" />
                <RadioButton toggleGroup="$myToggleGroup" mnemonicParsing="false" GridPane.columnIndex="1" GridPane.rowIndex="4" />
            </children>
        </GridPane>
        <Label fx:id="label" text="Label">
            <VBox.margin>
                <Insets top="30.0"/>
            </VBox.margin>
        </Label>
    </children>
</VBox>

最后是创建组件并绑定其属性的应用程序主类:

Finally the application main class that creates the components and binds their properties:

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

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        BgrdService bgrdService = new BgrdService();
        bgrdService.setPeriod(Duration.millis(3000.0));
        bgrdService.start();

        FXMLLoader loader = new FXMLLoader(this.getClass().getResource("Main.fxml"));
        MainController mainController = new MainController();
        loader.setController(mainController);
        Parent root = loader.load();

        mainController.valueProperty().bind(bgrdService.lastValueProperty());

        Scene scene = new Scene(root, 500, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

这篇关于JavaFX:如何使用Task将值从后台线程传递到JavaFX UI线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆