Так что я знаю, что уже есть много постов о подобных проблемах, но этот немного странный, и, поскольку я уже потратил 5 часов на эту проблему, я обращаюсь к своему последнему средству.
Все, что я пытаюсь сделать, - это создать 2 пользовательских компонента и поместить один из них в другой из файла f xml. Это должно быть очень просто, и я делал это раньше с другими типами компонентов, но по какой-то причине сейчас это не нравится. Взгляните,
SecondaryInterface.kt
import javafx.fxml.FXMLLoader
import javafx.scene.control.Label
import javafx.scene.layout.GridPane
import java.io.IOException
class SecondaryInterface : GridPane() {
@FXML private lateinit var label: Label
init {
println("From SecondaryInterface: ")
println("\t" + MainInterface::class.java)
println("\t" + javaClass.getResource("main_interface.fxml"))
println("\t" + javaClass.getResource("SecondaryInterface.kt"))
println("\t" + javaClass.getResource("secondary_interface.fxml"))
val fxmlLoader = FXMLLoader(javaClass.getResource("secondary_interface.fxml"))
fxmlLoader.setRoot(this)
fxmlLoader.setController(this)
try {
fxmlLoader.load<Any>()
} catch (exception: IOException) {
throw RuntimeException(exception)
}
}
}
вторичный_интерфейс.f xml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<fx:root type="javafx.scene.layout.GridPane" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml">
<Label fx:id="label" text="This is the secondary interface"></Label>
</fx:root>
Вторичным интерфейсом является вложенный компонент. Что-нибудь смотришь? Далее
MainInterface.kt
import javafx.fxml.FXML
import javafx.fxml.FXMLLoader
import javafx.scene.layout.GridPane
import java.io.IOException
class MainInterface : GridPane() {
@FXML private lateinit var secondInterface: SecondaryInterface
init {
println("From MainInterface: ")
println("\t" + MainInterface::class.java)
println("\t" + javaClass.getResource("main_interface.fxml"))
println("\t" + javaClass.getResource("SecondaryInterface.kt"))
println("\t" + javaClass.getResource("secondary_interface.fxml"))
val fxmlLoader = FXMLLoader(javaClass.getResource("main_interface.fxml"))
fxmlLoader.setRoot(this)
fxmlLoader.setController(this)
try {
fxmlLoader.load<Any>()
} catch (exception: IOException) {
throw RuntimeException(exception)
}
}
}
main_interface.f xml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import SecondaryInterface?>
<fx:root type="javafx.scene.layout.GridPane"
xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml">
<Label text="This is primary interface"></Label>
<SecondaryInterface fx:id="secondInterface"></SecondaryInterface>
</fx:root>
Вывод / Ошибка StackTrace
From MyApplication:
class MainInterface
file:/E:/Programming/Tests/NestedCustomComponents/out/production/NestedCustomComponents/main_interface.fxml
null
file:/E:/Programming/Tests/NestedCustomComponents/out/production/NestedCustomComponents/secondary_interface.fxml
From MainInterface:
class MainInterface
file:/E:/Programming/Tests/NestedCustomComponents/out/production/NestedCustomComponents/main_interface.fxml
null
file:/E:/Programming/Tests/NestedCustomComponents/out/production/NestedCustomComponents/secondary_interface.fxml
Exception in Application start method
Exception in thread "main" java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.RuntimeException: javafx.fxml.LoadException:
/E:/Programming/Tests/NestedCustomComponents/out/production/NestedCustomComponents/main_interface.fxml
at MainInterface.<init>(MainInterface.kt:24)
at MyApplication.start(MyApplication.kt:24)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
... 1 more
Caused by: javafx.fxml.LoadException:
/E:/Programming/Tests/NestedCustomComponents/out/production/NestedCustomComponents/main_interface.fxml
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2625)
at javafx.fxml.FXMLLoader.importClass(FXMLLoader.java:2863)
at javafx.fxml.FXMLLoader.processImport(FXMLLoader.java:2707)
at javafx.fxml.FXMLLoader.processProcessingInstruction(FXMLLoader.java:2676)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2542)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2466)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2435)
at MainInterface.<init>(MainInterface.kt:22)
... 10 more
Caused by: java.lang.ClassNotFoundException
at javafx.fxml.FXMLLoader.loadType(FXMLLoader.java:2914)
at javafx.fxml.FXMLLoader.importClass(FXMLLoader.java:2861)
... 16 more
Process finished with exit code 1
Я слишком долго анализировал это и не смог извлечь из этого ничего полезного -_-
Вот что я пробовал до сих пор:
- Двойная проверка соглашений об именах (имена пакетов в нижнем регистре и имена классов начинаются с заглавных букв)
- Повторная сборка проекта несколько раз
- Проверка правильности импорта
- Печать отладочного текста, такого как classpath, как видно из кода и вывода, чтобы проверить, заметны ли требуемые файлы (почему он не может найти мои файлы .kt, но может найти мои файлы .f xml?)
- Указание контроллера fx: в файлах .f xml
- Использование
internal constructor()
(после имени класса) - Объявление классов как
open
- Добавление аргументов VM
--module-path
C:\javafx-sdk-11.0.2\lib
--add-modules
javafx.controls,javafx.fxml
Это был более крупный проект, над которым я работаю. Я сократил все, чтобы упростить проблему.
Вот другие классы, которые вам нужны, если вы хотите попробовать сами,
Main.kt
import javafx.application.Application
fun main(args: Array<String>) {
Application.launch(MyApplication::class.java)
}
MyApplication.kt
import javafx.application.Application
import javafx.scene.Scene
import javafx.scene.layout.Pane
import javafx.stage.Stage
import MainInterface //Not imported because in same package
class MyApplication : Application() {
fun main(args: Array<String>) { launch(*args) }
override fun start(primaryStage: Stage) {
val mainScene = Scene(Pane(), 475.0, 425.0)
ScreenController.stage = primaryStage
ScreenController.scene = mainScene
ScreenController.bindSceneWithStage()
println("From MyApplication: ")
println("\t" + MainInterface::class.java)
println("\t" + javaClass.getResource("main_interface.fxml"))
println("\t" + javaClass.getResource("/SecondaryInterface.kt"))
println("\t" + javaClass.getResource("secondary_interface.fxml"))
ScreenController.addScene("mainInterface", MainInterface()) //Crashes here
ScreenController.stage!!.show()
ScreenController.activateScene("mainInterface")
}
}
ScreenController.kt
import javafx.scene.Scene
import javafx.scene.layout.Pane
import javafx.stage.Stage
import java.util.*
object ScreenController {
var stage: Stage? = null
var scene: Scene? = null
private val mapOfCustomPanes = mutableMapOf<String, Pane>()
fun bindSceneWithStage() {
stage!!.scene = scene!!
}
fun addScene(name: String, pane: Pane) {
mapOfCustomPanes[name] = pane
}
fun removeScene(name: String?) {
mapOfCustomPanes.remove(name)
}
fun activateScene(name: String?) {
scene!!.root = mapOfCustomPanes[name]
}
}
Любая помощь будет принята с благодарностью, так как я серьезно растерялся с этим. Спасибо