Прежде всего, я использую Kotlin в своем проекте JavaFX.
Я пытаюсь реализовать свой собственный узел JavaFX, который расширяет Canvas
.
class BrikkCanvas(width: Double, height: Double, private val rows: Int, private val cols: Int) : Canvas(width, height)
Я также хочу иметь возможность добавлять BrikkCanvas
непосредственно в файл FXML, например так
<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
, который расширяет 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
= else defaultBuilderFactory.getBuilder(clazz)
Обратите внимание, что я еще даже не включил теги <BrikkCanvas ... />
в файл FXML.
Я почти уверен, что мне не хватает чего-то действительно простого, что, вероятно, связано с тем, что я использую Kotlin вместо Java.