How do I catch and handle a TextField content change event?

There is a JavaFX project. The interface is described in an FXML file containing a TextField object:

<TextField fx:id="field" layoutX="95.0" layoutY="40.0" prefHeight="25.0" prefWidth="35.0" />

You need to handle the text change event in the field. I've seen how this is done if the TextField was created in java code, but how to do it when it is described in FXML is unclear. The "onInputMethodTextChanged" attribute in the TextField tag added:

onInputMethodTextChanged="#controller_method_name"

But, for some reason, the method is not called when entering text in the field (there are no errors). I would like to do this, according to possibly through some sort of specifying a handler method in the FXML itself right away (as with" onInputMethodTextChanged " tried).

Author: Alexey Lyulenkov, 2018-03-01

1 answers

Apparently, what you want in the java code of the controller would look like:

field.textProperty().addListener((observable, oldValue, newValue)->{...});

For JavaFX 8+ :

Especially for your case (for the ChangeListener property handler) , JavaFX 8 has made changes that allow you to write like this:

<TextField onTextChange="#method" />

At the same time, the method must have the following signature in the controller:

public void method(ObservableValue observable, String oldValue, String newValue) {
    System.out.println("textonchange2(): "+oldValue+" -> "+newValue);
}

Link to the documentation:

JavaFX 8. Introduction to FXML: Special handlers for collections and properties


The following is true for JavaFX 2.*:

(I leave as an example how to use javascript in FXML)

Unfortunately, the standard TextField doesn't have a property to do something like <TextField onTextChange="#..."/>.

Also, the textProperty property type is TextProperty, and there is no suitable JavaFX property in this class either (to try something like <TextField><text onChange="#..."/></TextField>).

It remains either to implement its own descendant class TextField, in to implement the desired functionality, or use some other workaround.

Of the workarounds, the least difficult, in my opinion, is to use the built-in javascript engine Nashorn:

// changetext.fxml:

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

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<?language javascript?>

<VBox xmlns="http://javafx.com/javafx"
            xmlns:fx="http://javafx.com/fxml"
            fx:controller="changetext.ChangetextController"
            prefHeight="400.0" prefWidth="600.0">
    <TextField fx:id="myTextField" text="Привет!"/>
    <fx:script>
        myTextField.textProperty()["addListener(javafx.beans.value.ChangeListener)"](
            function(observable, oldValue, newValue){
                print('observable: ' + observable);
                print(' oldValue: ' + oldValue);
                print(' newValue: ' + newValue);
                controller.js2controller(observable, oldValue, newValue);
            });
    </fx:script>
</VBox>

For this example, it is important that the script is located after the element - in this case, the object myTextField has already been created by FXMLLoader ' th.

You should also pay attention to specifying the signature when calling the addListener() method, because it has another one overloaded version with InvalidationListener.

The controller's Java methods are called from javascript via the controller object, which is added to the javascript global namespace FXMLLoader ' s when parsing the fx:controller attribute.

Related controller and application files:

// ChangetextController.java:

package changetext;

import javafx.beans.value.ObservableValue;
import javafx.scene.control.TextField;

public class ChangetextController {

    public TextField myTextField;

    public void js2controller(ObservableValue observable, String oldValue, String newValue) {
        System.out.println("js2controller(): " + oldValue + " -> " + newValue);
    }
}

// ChangeTextMain.java:

package changetext;

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

public class ChangeTextMain  extends Application {

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

    @Override
    public void start(Stage primaryStage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("changetext.fxml"));
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }
}
 1
Author: oshatrk, 2018-04-04 18:01:32