【问题标题】:How to fix 'IllegalStateException' when using custom JavaFXBuilderFactory使用自定义 JavaFXBuilderFactory 时如何修复“IllegalStateException”
【发布时间】:2019-08-19 09:44:32
【问题描述】:

首先,我在我的 JavaFX 项目中使用 Kotlin。

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

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)
    }
}

在扩展ApplicationApp 类中,我像这样使用我的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 = else defaultBuilderFactory.getBuilder(clazz)

请注意,我还没有在 FXML 文件中包含任何 &lt;BrikkCanvas ... /&gt; 标记

我很确定我错过了一些非常基本的东西,这可能与我使用 Kotlin 而不是 Java 的事实有关

【问题讨论】:

    标签: javafx kotlin fxml builder fxmlloader


    【解决方案1】:

    据我了解,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 属性对应于哪个参数,从而可以通过构造函数设置属性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-15
      • 1970-01-01
      相关资源
      最近更新 更多