Lesson 13

Threads II

Binding values is a mechanic which allows to implement dependencies in views quickly. Today we will connect it with a usage of classes handling concurrent programming in JavaFX.

I. Binding values


Task 0

We want to show a text in a Label which jest inserted in a TextField. We are not going to use any events nor buttons.


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

<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane
    prefHeight="160.0"
    prefWidth="644.0"
    xmlns="http://javafx.com/javafx/8.0.121"
    xmlns:fx="http://javafx.com/fxml/1"
    fx:controller="sample.Controller">

    <TextField
        fx:id="textField"
        layoutX="14.0"
        layoutY="14.0" />

    <Label
        fx:id="label"
        layoutX="195.0"
        layoutY="19.0" />

</AnchorPane>


import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;

public class Controller {

    @FXML
    private TextField textField;

    @FXML
    private Label label;

    public void initialize() {
        label.textProperty().bind(textField.textProperty());
    }

}

Execute a code, look at a usage of bind. What is binded with what? Can we swap the instruction?

Task 1 (At home, to practise, not for a grade)

Write an application which uses binding. It will allow to change the location of starting and ending point of a line only by using sliders.

Binding task

II. Preparing a scene


Task 2

Prepare a view in your application:


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

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ProgressBar?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Text?>

<AnchorPane
    xmlns:fx="http://javafx.com/fxml/1"
    prefHeight="196.0"
    prefWidth="969.0"
    xmlns="http://javafx.com/javafx/8.0.121"
    fx:controller="Controller">

    <Text
        fx:id="name"
        layoutX="27.0"
        layoutY="43.0"
        strokeType="OUTSIDE"
        strokeWidth="0.0"
        text="Progress"
        wrappingWidth="210" />
    
    <ProgressBar
        fx:id="progress"
        layoutX="25.0"
        layoutY="126.0"
        prefHeight="20.0"
        prefWidth="958.0"
        progress="0.0"
        AnchorPane.leftAnchor="25.0"
        AnchorPane.rightAnchor="25.0" />

</AnchorPane>
Task 3

Task class allows to create a task which is executed once (it can be restarted). It allows JavaFX to synchronize its work.


import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.scene.control.ProgressBar;
import javafx.scene.text.Text;

public class Controller {

    // A keyword final means that,
    // variable's value cannot be changed
    public static final int VALUTE_TO_COMPLETE = 1000;

    @FXML
    private Text name;

    @FXML
    private ProgressBar progress;

    @FXML
    public void initialize() {

        // Create a task
        Task progressTask = new Task() {
            @Override
            protected Integer call() throws Exception {
                int value = 0;
                while (value < VALUTE_TO_COMPLETE) {
                    value++;
                    updateMessage("Reached value: " + value);
                    updateProgress(value, VALUTE_TO_COMPLETE);
                    Thread.sleep(100);
                }
                return value;
            }
        };

        // Bind values
        progress.progressProperty().bind(progressTask.progressProperty());
        name.textProperty().bind(progressTask.messageProperty());

        // Start
        Thread thread = new Thread(progressTask);
        thread.setDaemon(true);
        thread.start();

    }

}

Execute a code, next analyze it.

III. Stopping a task when we want it


Task 4

Prepare a view in your application:


<Button
    layoutX="712.0"
    layoutY="25.0"
    minHeight="77.0"
    minWidth="238.0"
    mnemonicParsing="false"
    onAction="#stop"
    prefHeight="77.0"
    prefWidth="238.0"
    text="Stop" />
Task 5

Task class allows to check if our task riched "Cancelled" state. In that case we have to stop further calculations. Do not forget we also have to stop them if we reach the maximum value.



// We check in a loop it a task is not cancelled
// from the outside
Task<Integer> progressTask = new Task<Integer>() {
    @Override
    protected Integer call() throws Exception {
        int value = 0;
        while (!isCancelled()) {
            value++;
            updateMessage("Reached value: " + value);
            updateProgress(value, VALUTE_TO_COMPLETE);
            Thread.sleep(100);
            if (value >= VALUTE_TO_COMPLETE) return value;
        }
        return value;
    }
};

// Method connected with a button.
@FXML
public void stop() {
    progressTask.cancel();
}

Analyze presented code. Copy 3 fragments of code, so you can force cancelling the task. Remember about variables visibility.

Task 6

Write "Boom" application which contains:

  • Timer which shows time left
  • Proceeding progress bar
  • A puzzle to solve.

If user solves a puzzle, timer stops (so does the progress bar).