JavaFX: Red border for text field

后端 未结 4 2015
生来不讨喜
生来不讨喜 2020-12-28 17:52

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,

相关标签:
4条回答
  • 2020-12-28 18:27

    The above mentioned solution by James_D works perfectly fine ( but not for JAVAFX 8.0 ). James have already mentioned the code changes for JAVAFX 8.0, i just tried that and it works like a charm. Here is the changed version for JAVAFX 8.0, just incase someone needs a quick reference.All CREDIT GOES TO JAMES_D

    import java.util.Collections;
    
    import javafx.application.Application;
    import javafx.beans.value.ChangeListener;
    import javafx.beans.value.ObservableValue;
    import javafx.collections.ObservableList;
    import javafx.css.PseudoClass;
    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 {
    private final PseudoClass errorClass = PseudoClass.getPseudoClass("error");
    @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) {
            tf.pseudoClassStateChanged(errorClass, true);
        }
        else{
            tf.pseudoClassStateChanged(errorClass, false);
        }
    
    }
    
    public static void main(String[] args) {
        launch(args);
    }
    

    }

    0 讨论(0)
  • 2020-12-28 18:31

    When using the javafx8 moderna style, you can use this css to make the border similar to the 'on focus' blue border:

    .text-input.error {
        -fx-focus-color: #d35244;
        -fx-faint-focus-color: #d3524422;
    
        -fx-highlight-fill: -fx-accent;
        -fx-highlight-text-fill: white;
        -fx-background-color:
            -fx-focus-color,
            -fx-control-inner-background,
            -fx-faint-focus-color,
            linear-gradient(from 0px 0px to 0px 5px, derive(-fx-control-inner-background, -9%), -fx-control-inner-background);
        -fx-background-insets: -0.2, 1, -1.4, 3;
        -fx-background-radius: 3, 2, 4, 0;
        -fx-prompt-text-fill: transparent;
    }
    

    add the css as classpath resource and load it using:

    scene.getStylesheets().add(
        getClass().getClassLoader().getResource(<your css resource path>).toString());
    

    then apply it to text fields using:

    // add error class (red border)
    textField.getStyleClass().add("error");
    // remove error class (red border)
    textField.getStyleClass().remove("error");
    
    0 讨论(0)
  • 2020-12-28 18:41

    With this it now works pefectly fine (it doesn't even need "setUpValidation"):

    public void initialize(URL arg0, ResourceBundle arg1) {
        removeRed(tfFirstName);
        removeRed(tfLastName);
    }
    
    public void OKButtonClicked() {
        try{
            //also: call validation class here
            removeRed(tfFirstName);
            removeRed(tfLastName);
        } catch(ValidationException e) {
            setRed(tfFirstName);
            setRed(tfLastName);
        }
    
    }
    
    private void setRed(TextField tf) {
        ObservableList<String> styleClass = tf.getStyleClass();
    
        if(!styleClass.contains("tferror")) {
            styleClass.add("tferror");
        }
    }
    
    
    private void removeRed(TextField tf) {
        ObservableList<String> styleClass = tf.getStyleClass();
        styleClass.removeAll(Collections.singleton("tferror"));
    }
    

    And in the css I added the following (unfortunately it didn't change the border width with "-fx-border-width: 2px" anymore):

    .tferror {  
         -fx-text-box-border: red ;
         -fx-focus-color: red ;   
    }
    
    0 讨论(0)
  • 2020-12-28 18:43

    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.)

    0 讨论(0)
提交回复
热议问题