I have one worker task which continuously consumes web service and returns integer value.
My Application consist of different (30) text boxes with associated radio butto
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.
Given the following service:
import javafx.concurrent.ScheduledService;
import javafx.concurrent.Task;
public class BgrdService extends ScheduledService<String> {
@Override protected Task<String> createTask() {
return new BgrdTask();
}
}
... and task:
import java.util.Date;
import javafx.concurrent.Task;
class BgrdTask extends Task<String> {
@Override protected String call() throws Exception {
return new Date().toString();
}
}
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; }
}
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);
}
}