如何创建自定义的FX组件以使其动态地呈现子级?

我有一个代表表单字段的自定义组件。它具有标签,文本字段和错误消息,输入验证后可能会显示该消息。

<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="109.0" prefWidth="512.0" spacing="10.0" styleclass="vbox" type="VBox" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <Label fx:id="fieldLabel" text="Lorem ipsum dolor sit amet"></Label>
      <TextField fx:id="textField" promptText="Lorem ipsum dolor sit amet"></TextField>
      <Label fx:id="errorLabel" text=""></Label>
   </children>
</fx:root>
public class FormField extends VBox {

    @FXML private TextField textField;
    @FXML private Label fieldLabel;
    @FXML private Label errorLabel;

    private String fieldLabelText;
    private String promptText;

    public FormField(@NamedArg("fieldLabelText") String fieldLabelText,@NamedArg("promptText") String promptText,@NamedArg("isPasswordField") boolean isPasswordField) {

        FXMLLoader loader = new FXMLLoader(getclass().getResource("../../resources/fxml/form-field.fxml"));
        loader.setRoot(this);
        loader.setController(this);

        this.fieldLabelText = fieldLabelText;
        this.promptText = promptText;

        try {
            loader.load();
        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }
    }

    @FXML
    public void initialize() {
        this.fieldLabel.setText(fieldLabelText);
        this.textField.setPromptText(promptText);
    }

现在我想知道的是如何对具有PasswordField而不是TextField的组件进行扩展?还是传递诸如boolean isPasswordField之类的参数,让FormField决定应呈现TextField还是PasswordField?如果TextField的API中有一个obscureText(true)方法,那就足够了,因为这就是我要寻找的全部,但是我找不到任何东西。

我能找到的关于JavaFX继承的全部含义是通过向对象添加新组件而不是通过更改其现有元素来“扩展”对象。

iCMS 回答:如何创建自定义的FX组件以使其动态地呈现子级?

一种选择是将TextFieldPasswordField都放置在UI中,并以StackPane的形式堆叠在一起,只有其中一个可见:

<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="109.0" prefWidth="512.0" spacing="10.0" styleClass="vbox" type="VBox" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <Label fx:id="fieldLabel" text="Lorem ipsum dolor sit amet"></Label>
      <StackPane>
        <TextField fx:id="textField" promptText="Lorem ipsum dolor sit amet"></TextField>
        <PasswordField fx:id="passwordField" visible="false"/>
      </StackPane>
      <Label fx:id="errorLabel" text=""></Label>
   </children>
</fx:root>

然后,控制器中的参数基于所传递的参数确定哪些可见:

public class FormField extends VBox {

    @FXML private TextField textField;
    @FXML private PasswordField passwordField;
    @FXML private Label fieldLabel;
    @FXML private Label errorLabel;

    private String fieldLabelText;
    private String promptText;
    private boolean isPasswordField;

    public FormField(@NamedArg("fieldLabelText") String fieldLabelText,@NamedArg("promptText") String promptText,@NamedArg("isPasswordField") boolean isPasswordField) {

        // path is copied from OP,but is incorrect:
        FXMLLoader loader = new FXMLLoader(getClass().getResource("../../resources/fxml/form-field.fxml"));
        loader.setRoot(this);
        loader.setController(this);

        this.fieldLabelText = fieldLabelText;
        this.promptText = promptText;
        this.isPasswordField = passwordField;

        try {
            loader.load();
        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }
    }

    @FXML
    public void initialize() {
        this.fieldLabel.setText(fieldLabelText);
        this.textField.setPromptText(promptText);
        this.passwordField.promptTextProperty().bind(
            this.textField.promptTextProperty());
        this.passwordField.setVisible(isPasswordField);
        this.textField.setVisible(!isPasswordField);
    }

}

其他变化也是可能的,例如您的FXML可以只定义StackPane,不包含任何内容;然后在控制器代码中根据需要添加TextFieldPasswordField

本文链接:https://www.f2er.com/2067648.html

大家都在问