使用自定义JavaFXBuilderFactory时如何修复“ IllegalStateException”

时间:2019-08-19 09:44:32

标签: javafx kotlin fxml builder fxmlloader

首先,我在JavaFX Project中使用Kotlin。

我正在尝试实现扩展Canvas的自己的JavaFX Node。

class BrikkCanvas(width: Double, height: Double, private val rows: Int, private val cols: Int) : Canvas(width, height)

我也希望能够像这样直接在FXML文件中添加BrikkCanvas

<BrikkCanvas fx:id="myCanvas" width="100.0" height="100.0" rows="1" cols="1" />

我的类没有默认的构造函数,这就是为什么在FXML中包含它并不容易。

但是我发现您可以实现自定义BuilderFactory,所以我做到了:

class BrikkCanvasBuilderFactory : BuilderFactory {
    private val defaultBuilderFactory = JavaFXBuilderFactory()

    override fun getBuilder(clazz: Class<*>): Builder<*> =
            if (clazz == BrikkCanvas::class.java) BrikkCanvasBuilder()
            else defaultBuilderFactory.getBuilder(clazz)

    private class BrikkCanvasBuilder : Builder<BrikkCanvas> {
        var width: Double = 0.0
        var height: Double = 0.0
        var rows: Int = 0
        var cols: Int = 0

        override fun build(): BrikkCanvas = BrikkCanvas(width, height, rows, cols)
    }
}

在扩展App的{​​{1}}类中,我像这样使用Application

BrikkCanvasBuilderFactory

但是,当我启动应用程序并单击调用fun startTheGame(playerName: String) { val loader = FXMLLoader(App::class.java.getResource("game.fxml"), null, BrikkCanvasBuilderFactory()) val scene = Scene(loader.load()) val controller = loader.getController<GameController>() primaryStage.scene = scene } 的按钮时,出现以下错误:

startTheGame

Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException ... Caused by: java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:567) ... Caused by: javafx.fxml.LoadException: /path to project/target/classes/game.fxml:21 at App$Companion.startTheGame(App.kt:18) ... Caused by: java.lang.IllegalStateException: defaultBuilderFactory.getBuilder(clazz) must not be null at controller.BrikkCanvasBuilderFactory.getBuilder(BrikkCanvasBuilderFactory.kt:12) = game.fxml:21 fx:controller="controller.GameController" = App$Companion.startTheGame(App.kt:18) val scene = Scene(loader.load()) = BrikkCanvasBuilderFactory.kt:12

请注意,我甚至还没有在FXML文件中包含任何else defaultBuilderFactory.getBuilder(clazz)标签

我很确定我缺少了一些真正的基本知识,这可能与我使用Kotlin而不是Java

有关。

1 个答案:

答案 0 :(得分:0)

据我所知,BuilderFactoryBuilder接口是过去的遗物(实质上已弃用),应在新代码中避免使用,以防它们不存在。您应该改为使用@NamedArg注释来注释构造函数参数。

class BrikkCanvas(
    @NamedArg("width") width: Double,
    @NamedArg("height") height: Double,
    @param:NamedArg("rows") private val rows: Int,
    @param:NamedArg("cols") private val cols: Int
) : Canvas(width, height)

FXMLLoader随后将能够分辨出哪个FXML属性与哪个参数相对应,从而可以通过构造函数设置属性。