JavaFX: Red border for text field


Question

I have a form with text fields and I want to give them a red border if I click on "save" but e.g. nothing was input in required fields, letters for the "birthday" field,... .

My files: EditController.java, error.css

I already tried:

tfFirstName.getStyleClass().add("error");

, to remove it if they enter something valid:

tfFirstName.getStyleClass().remove("error");

and in the css:

.text-field.error {  
 -fx-border-color: red ;  
 -fx-border-width: 2px ;  
}

But it didn't change anything.

Surprisingly,

tfFirstName.setStyle("-fx-border-color: red ; -fx-border-width: 2px ;");

(and an empty string to get rid of it) works just fine but it isn't "pretty" if I want to add more to it later.

Does anyone know how to fix the css?

1
10
6/15/2014 4:59:56 PM

Try

.text-field.error {
  -fx-text-box-border: red ;
  -fx-focus-color: red ;
}

The first sets the border color when it's not focussed, the second when it is focussed.

With this in the stylesheet text-field-red-border.css, the following example works:

import java.util.Collections;

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;

public class ValidatingTextFieldExample extends Application {

    @Override
    public void start(Stage primaryStage) {
        GridPane root = new GridPane();
        TextField nameTF = new TextField();
        TextField emailTF = new TextField();

        root.add(new Label("Name:"), 0, 0);
        root.add(nameTF, 1, 0);
        root.add(new Label("Email:"), 0, 1);
        root.add(emailTF, 1, 1);

        setUpValidation(nameTF);
        setUpValidation(emailTF);

        Scene scene = new Scene(root, 250, 150);
        scene.getStylesheets().add(getClass().getResource("text-field-red-border.css").toExternalForm());
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private void setUpValidation(final TextField tf) { 
        tf.textProperty().addListener(new ChangeListener<String>() {

            @Override
            public void changed(ObservableValue<? extends String> observable,
                    String oldValue, String newValue) {
                validate(tf);
            }

        });

        validate(tf);
    }

    private void validate(TextField tf) {
        ObservableList<String> styleClass = tf.getStyleClass();
        if (tf.getText().trim().length()==0) {
            if (! styleClass.contains("error")) {
                styleClass.add("error");
            }
        } else {
            // remove all occurrences:
            styleClass.removeAll(Collections.singleton("error"));                    
        }
    }

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

By the way, if you are using JavaFX 8, favor pseudoclasses over setting the class directly, as it's cleaner (you don't need all the ugly code checking that you only add the style class once and/or remove all occurrences of it) and more efficient. To set and unset the pseudoclass do:

final PseudoClass errorClass = PseudoClass.getPseudoClass("error");

tfFirstName.pseudoClassStateChanged(errorClass, true); // or false to unset it

Then the css should be

.text-field:error {
  -fx-text-box-border: red ;
  -fx-focus-color: red ;
}

(Note the colon instead of the . between -text-field and error.)

18
6/15/2014 7:13:40 PM

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon