JavaFX将FXML生成的节点更改为另一个节点

JavaFX将FXML生成的节点更改为另一个节点,java,javafx,fxml,controlsfx,Java,Javafx,Fxml,Controlsfx,我有一个由fxml文件定义的复杂UI。有很多库存TextFields,我想换成图书馆提供的更高级版本(可清除文本字段) 问题是: ControlsFX使用CustomTextField提供高级功能,但它只能由TextFields.createClearableTextField()初始化,只能从代码中调用 我正在寻找一种方法,将通过FXML初始化的TextFields与从代码初始化的CustomTextFields进行交换,以便这些新控件保留FXML中定义的所有布局属性 在FXML中定义Cust

我有一个由fxml文件定义的复杂UI。有很多库存
TextField
s,我想换成图书馆提供的更高级版本(可清除文本字段)

问题是:

ControlsFX使用
CustomTextField
提供高级功能,但它只能由
TextFields.createClearableTextField()
初始化,只能从代码中调用

我正在寻找一种方法,将通过FXML初始化的
TextField
s与从代码初始化的
CustomTextField
s进行交换,以便这些新控件保留FXML中定义的所有布局属性

在FXML中定义
CustomTextField
也没有帮助,因为默认情况下它是无用的。
CustomTextField
通过
private static void setupclearbutonfield(TextField inputField,ObjectProperty rightProperty)
获得它的特性,我不能调用它,因为它是私有的

控制SFX代码:

/**
 * Creates a TextField that shows a clear button inside the TextField (on
 * the right hand side of it) when text is entered by the user.
 */
public static TextField createClearableTextField() {
    CustomTextField inputField = new CustomTextField();
    setupClearButtonField(inputField, inputField.rightProperty());
    return inputField;
}

/**
 * Creates a PasswordField that shows a clear button inside the PasswordField
 * (on the right hand side of it) when text is entered by the user.
 */
public static PasswordField createClearablePasswordField() {
    CustomPasswordField inputField = new CustomPasswordField();
    setupClearButtonField(inputField, inputField.rightProperty());
    return inputField;
}

private static void setupClearButtonField(TextField inputField, ObjectProperty<Node> rightProperty) {
    inputField.getStyleClass().add("clearable-field"); //$NON-NLS-1$

    Region clearButton = new Region();
    clearButton.getStyleClass().addAll("graphic"); //$NON-NLS-1$
    StackPane clearButtonPane = new StackPane(clearButton);
    clearButtonPane.getStyleClass().addAll("clear-button"); //$NON-NLS-1$
    clearButtonPane.setOpacity(0.0);
    clearButtonPane.setCursor(Cursor.DEFAULT);
    clearButtonPane.setOnMouseReleased(e -> inputField.clear());
    clearButtonPane.managedProperty().bind(inputField.editableProperty());
    clearButtonPane.visibleProperty().bind(inputField.editableProperty());

    rightProperty.set(clearButtonPane);

    final FadeTransition fader = new FadeTransition(FADE_DURATION, clearButtonPane);
    fader.setCycleCount(1);

    inputField.textProperty().addListener(new InvalidationListener() {
        @Override public void invalidated(Observable arg0) {
            String text = inputField.getText();
            boolean isTextEmpty = text == null || text.isEmpty();
            boolean isButtonVisible = fader.getNode().getOpacity() > 0;

            if (isTextEmpty && isButtonVisible) {
                setButtonVisible(false);
            } else if (!isTextEmpty && !isButtonVisible) {
                setButtonVisible(true);
            }
        }

        private void setButtonVisible( boolean visible ) {
            fader.setFromValue(visible? 0.0: 1.0);
            fader.setToValue(visible? 1.0: 0.0);
            fader.play();
        }
    });
}
/**
*创建一个文本字段,显示文本字段内的清除按钮(打开
*当用户输入文本时,它的右侧)。
*/
公共静态文本字段createClearableTextField(){
CustomTextField inputField=新建CustomTextField();
setupClearButtonField(inputField,inputField.rightProperty());
返回输入字段;
}
/**
*创建一个PasswordField,它在PasswordField内显示一个clear按钮
*(在它的右侧)当用户输入文本时。
*/
公共静态密码字段createClearablePasswordField(){
CustomPasswordField inputField=新CustomPasswordField();
setupClearButtonField(inputField,inputField.rightProperty());
返回输入字段;
}
私有静态无效设置ClearButtonField(TextField inputField,ObjectProperty rightProperty){
inputField.getStyleClass().add(“可清除字段”);//$NON-NLS-1$
区域clearButton=新区域();
clearButton.getStyleClass().addAll(“图形”);/$NON-NLS-1$
StackPane clearButtonPane=新的StackPane(clearButton);
clearButtonPane.getStyleClass().addAll(“清除按钮”);//$NON-NLS-1$
clearButtonPane.setOpacity(0.0);
clearButtonPane.setCursor(Cursor.DEFAULT);
clearButtonPane.setOnMouseReleased(e->inputField.clear());
clearButtonPane.managedProperty().bind(inputField.editableProperty());
clearButtonPane.visibleProperty().bind(inputField.editableProperty());
rightProperty.set(clearButtonPane);
最终淡入淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡出淡;
音量控制器设置周期计数(1);
inputField.textProperty().addListener(新的InvalizationListener(){
@覆盖公共无效(可观察arg0){
String text=inputField.getText();
布尔值isTextEmpty=text==null | | text.isEmpty();
布尔值isButtonVisible=fader.getNode().getOpacity()>0;
如果(IsExtenty&&isButtonVisible){
setButtonVisible(假);
}如果(!IsExtenty&!isButtonVisible)为else,则为{
setButtonVisible(真);
}
}
私有void setButtonVisible(布尔可见){
音量控制器.setFromValue(可见?0.0:1.0);
音量控制器设置值(可见?1.0:0.0);
fader.play();
}
});
}

您可以使用中所述的
fx:factory


然后在控制器中使用它:

package com.example;

import javafx.fxml.FXML;
import javafx.scene.control.TextField;

public class Controller {

    @FXML private TextField field;

}
注意:如果您使用IntelliJ,它将发出一个错误,说明:

无法将org.controlsfx.control.textfield.TextFields设置为字段“field”


在FXML文件中,但是当我运行一个测试项目时,一切都正常工作。

当您在代码和FXML中使用CustomTextField代替TextField时会发生什么
createClearableTextField()
返回一个TextField,因此似乎格式化和放置应该继续正常工作。不幸的是,它无法加载带有
java.lang.NoSuchMethodException
的FXML文件。它试图将
createClearableTextField()
作为
javafx.scene.control.TextField
的静态方法加载,但它存在于
org.controlsfx.control.TextField.TextFields
中。我通过创建
类MyTextField扩展TextField
并提供
公共静态TextField create()克服了这个问题{return TextFields.createClearableTextField()
}。然后我在FXML文件中编写了
。我无法重现这个问题,即使我同时导入了
TextField
TextFields
;我尝试了JavaFX 8u202、JavaFX 11.0.2和JavaFX 12。你确定你没有打字错误吗(例如,
TextField
而不是
TextFields
)?可以确认,它在Intellij Community 2020.3的JavaFX 15.0.1和ControlsFX 11.0.3上工作,谢谢!