JavaFX 中的选择边框。想要使用 CSS 更改默认行为

Selection Border in JavaFX. Wanting to change default behavior with CSS

我正在使用在我的 TextFields 周围放置红色边框的验证

nameTF.setStyle("-fx-text-box-border: red;");

并使用

将其恢复为默认值

nameTF.setStyle("-fx-text-box-border: #D3D3D3;");

我正在尝试使用 CSS: 希望增加边框的宽度,使焦点边框在我的红色验证边框之外 inside/or(所以都显示)。现在,当我单击一个单元格时,选择边框会替换当前边框颜色和宽度...?

.text-input {
 -fx-border-color: #D3D3D3;
-fx-border-width: 3 ;
 }

.text-field:focused{
 -fx-border-color: blue ;
 -fx-border-width: 1 ;
}

此外,我注意到通过使用

.text-input {
 -fx-border-color: #D3D3D3;
-fx-border-width: 3 ;
 }

红色 nameTF.setStyle("-fx-text-box-border: red;"); 根本不出现?

发生了什么事以及我希望得到什么:

谢谢!

建议的方法

我建议您查看如何 controlsfx accomplishes this 并使用该库或通过研究他们的源代码(如果适用)来学习他们的方法。

我检查了 controlsfx validation code which applies style classes for validation feedback. The sample usage provides feedback via css drop shadow effects。这是一个简单的解决方案,比自定义背景更容易。

我尝试使用投影效果来标记无效的文本字段,它似乎对我很有效。

对于除文本字段以外的复杂控件(如范围滑块,其中范围刻度文本也被遮蔽),投影方法看起来有点奇怪,所以也许对于那些,您可能想要做一些更复杂的事情。

示例应用程序

这会根据需要在字段上设置或取消设置 invalid 样式 class。

.invalid {
    -fx-effect: dropshadow(three-pass-box, tomato, 3, 0.8, 0, 0);
}

invalid 样式 class 处于活动状态时会触发投影效果,以向用户提供该字段无效的指示。

参考CSS effect documentation了解投影效果的设置。

焦点值无效:

没有焦点的无效值:

焦点有效值:

没有焦点的有效值:

此示例并不是一个强大的验证框架,它只是一个示例,用于展示您可以如何为文本字段提供验证反馈样式。

该示例基于标准样式 class 运行,但如果您想研究它,则可以使用 。例如,类似于 :focus psuedo-class,您可以实现 CSS :invalid psuedo-class.

import javafx.application.Application;
import javafx.geometry.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;

public class ValidatorApp extends Application {

    public static final String CSS = "data:text/css," + // language=CSS
            """
            .invalid {
                -fx-effect: dropshadow(three-pass-box, tomato, 3, 0.8, 0, 0);
            }
            """;

    @Override
    public void start(Stage stage) throws Exception {
        TextField integerTextField = new TextField();

        IntegerTextFieldValidator validator = new IntegerTextFieldValidator();

        validator.validate(integerTextField);
        integerTextField.textProperty().addListener(o -> 
                validator.validate(integerTextField)
        );

        VBox layout = new VBox(10,
                labelField("Enter an integer: ", integerTextField),
                labelField("Enter any value:  ", new TextField("foobar"))
        );
        layout.setPadding(new Insets(10));

        Scene scene = new Scene(layout);
        scene.getStylesheets().add(CSS);

        stage.setScene(scene);
        stage.show();
    }

    HBox labelField(String labelText, Node field) {
        HBox box = new HBox(10, new Label(labelText), field);
        box.setAlignment(Pos.BASELINE_LEFT);

        return box;
    }

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

import javafx.scene.Node;
import javafx.scene.control.TextField;

public class IntegerTextFieldValidator {
    private static final String INVALID_STYLECLASS = "invalid";

    public void validate(TextField textField) {
        String text = textField.getText();

        if (text == null) {
            setInvalid(textField);
            return;
        }

        try {
            Integer.parseInt(text);
            setValid(textField);
        } catch (NumberFormatException e) {
            setInvalid(textField);
        }
    }

    private void setInvalid(Node node) {
        if (!node.getStyleClass().contains(INVALID_STYLECLASS)) {
            node.getStyleClass().add(INVALID_STYLECLASS);
        }
    }

    private void setValid(Node node) {
        node.getStyleClass().removeAll(INVALID_STYLECLASS);
    }
}