JavaFXML创建不扩展节点的自定义标记元素

JavaFXML创建不扩展节点的自定义标记元素,java,javafx,javafx-8,javafx-2,fxml,Java,Javafx,Javafx 8,Javafx 2,Fxml,我想为我的fxml文件创建一个自定义标记/元素,但我不想强制此元素从窗格、按钮、文本字段等继承。在我的自定义元素中是否有一些可以实现的接口需要我实现,比如说fx()方法,该方法需要返回一个节点/区域元素,该元素应该在场景中渲染。我的意思是 如果有可能做到以下几点 public class CustomElement implements SOME_FXML_INTERFACE { private String myArg; public CustomElement(@Name

我想为我的
fxml
文件创建一个自定义
标记
/
元素
,但我不想强制此元素从
窗格
按钮
文本字段
等继承。在我的自定义元素中是否有一些可以实现的接口需要我实现,比如说
fx()
方法,该方法需要返回一个
节点
/
区域
元素,该元素应该在
场景
中渲染。我的意思是 如果有可能做到以下几点

public class CustomElement implements SOME_FXML_INTERFACE {

    private String myArg;

    public CustomElement(@NamedArg("myArg") myArg) {
        this.myArg = myArg;
    }

    // method that is required to be implemented by SOME_FXML_INTERFACE
    // this method retuns some GUI element which actually needs to be rendered in the Scene
    @Override
    public Object fx() {
        return new TextField(myArg);
    }

}


<HBox>
    <CustomElement myArg="some_argument"/>
</HBox>
public类CustomElement实现了一些\u FXML\u接口{
私有字符串myArg;
公共CustomElement(@NamedArg(“myArg”)myArg){
this.myArg=myArg;
}
//方法,该方法需要由某些\u FXML\u接口实现
//此方法重新运行一些实际需要在场景中渲染的GUI元素
@凌驾
公共对象fx(){
返回新的文本字段(myArg);
}
}

所有这些都是为了让
CustomElement
可以接受构造函数中的自定义参数。

您可以创建任意对象,但factory对象只能由支持此功能的节点使用。(从技术上讲,您可以这样做,但这需要使用getter在每次调用它时返回一个新实例。)但是,您可以使用自定义类作为
cellFactory
,用于
ListView

如果您不需要依赖实例方法,但对
static
factory方法感到满意,则可以使用
fx:factory
标记指定创建节点实例的方法,而无需实现任何接口:

package my.package;

...

public class CustomElement {

    public static Node fx() {
        return new TextField(myArg);
    }

}

更多信息可在

顺便说一句:如果你的类有一个不带任何参数的
public
构造函数,你只需在fxml中添加一个带有类名称的元素,就可以创建该类的实例。例如,加载时,以下fxml会导致
ArrayList
;但是,您可以使用这些实例的方式是有限的


以及使用工厂方法,您可以重新调整生成器机制的用途来实现这一点。与
一样,它仅限于不带参数的
静态方法,使用有点有限。但是,下面是一个示例工厂/生成器,它创建一个
文本字段
标签
,具体取决于是否设置了
可编辑
标志:

package org.jamesd.examples.fxmlfactory;

import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.util.Builder;

public class Factory implements Builder<Node> {

    private String text = "" ;
    private boolean editable = false ;



    public String getText() {
        return text;
    }



    public void setText(String text) {
        this.text = text;
    }



    public boolean isEditable() {
        return editable;
    }



    public void setEditable(boolean editable) {
        this.editable = editable;
    }



    @Override
    public Node build() {
        if (editable) {
            return new TextField(text);
        } else {
            return new Label(text);
        }
    }


}
然后将其注册到
FXMLLoader

package org.jamesd.examples.fxmlfactory;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class App extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {

        FXMLLoader loader = new FXMLLoader(getClass().getResource("Example.fxml"));
        loader.setBuilderFactory(new NodeBuilderFactory());
        Parent root = loader.load();
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

}

您希望返回什么节点而不是扩展节点?我已将
fx()
返回类型更改为
Object
,因为它不会以以前编写的方式编译。我不想扩展节点,因为这会带来节点的开销属性/方法,而我不会使用这些属性/方法。@SamOrozco有很多很好的理由选择聚合而不是继承。例如,您可能不想提交您要返回的
节点类型(允许在更高版本中从一种节点类型更改为另一种,并确保没有代码会中断);或者,您可能希望根据某些条件返回不同类型的节点。子类化特定节点将不允许您这样做;子类化
节点
本身不允许您,例如,提供
文本字段
package org.jamesd.examples.fxmlfactory;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class App extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {

        FXMLLoader loader = new FXMLLoader(getClass().getResource("Example.fxml"));
        loader.setBuilderFactory(new NodeBuilderFactory());
        Parent root = loader.load();
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

}