Search code examples
javafxjavafx-8fxml

Listen to changes in TextField defined in FXML


I am writing a simpe login GUI that is composed by a GridPane, which is the main container, then a TextField which takes in the user nickname and finally a login Button.

I wrote the GUI structure in FXML combined with CSS.

What I wanted to do was keeping the login Button disabled until the user actually wrote something in the TextField. I could only find an answer related to this but I wanted to know what was the best method to put this Listener in the FXML code itself so that I could get a cleaner code in the FXML controller.

I tried to use the method onKeyTyped but that didn't do the work cause I get no response whenever I'm typing in the TextField.

This is my FXML code

<TextField fx:id="usernameTextField"
           promptText="Username"
           onKeyTyped="#userTyped"
           stylesheets="@loginStyle.css">

What's the best method to achieve this?


Solution

  • In general, if you want to perform an action if the text of a text field changes, you need to register a listener with the text field's textProperty(), which you haver to do in the controller:

    @FXML
    private TextField usernameTextField ;
    
    public void initialize() {
        usernameTextField.textProperty().addListener((obs, oldText, newText) -> {
            // do what you need with newText here, e.g.
            loginButton.setDisable(newText.isEmpty());
        });
    }
    

    However, if all you need is to bind a property in one control to a property in another control (or some simple dependency of that property), you can use FXML expression binding:

    <TextField fx:id="usernameTextField"/>
    <Button text="Login" disable="${usernameTextField.text.empty}" />
    

    Here's a SSCCE:

    ButtonDisableTest.fxml:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import javafx.scene.layout.VBox?>
    <?import javafx.scene.control.TextField?>
    <?import javafx.scene.control.Button?>
    
    <VBox alignment="CENTER" spacing="5" xmlns:fx="http://javafx.com/fxml/1">
        <TextField fx:id="usernameTextField"/>
        <Button text="Login" disable="${usernameTextField.text.empty}" />
    </VBox>
    
    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.stage.Stage;
    
    public class ButtonDisableTest extends Application {
    
        @Override
        public void start(Stage primaryStage) throws Exception {
            Parent root = FXMLLoader.load(getClass().getResource("ButtonDisableTest.fxml"));
            Scene scene = new Scene(root, 400, 400);
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    enter image description here