Scene Builder Вложенные пользовательские узлы - PullRequest
0 голосов
/ 23 мая 2018

Кажется, я столкнулся с довольно серьезной ошибкой в ​​Scene Builder 8.4.1, с которой другие люди сталкивались ранее для разных версий (см. эту ссылку).Ошибка заключается в том, что когда я пытаюсь импортировать пользовательский узел, который в свою очередь содержит другие пользовательские узлы из файла JAR, обнаруживаются только вложенные узлы.То есть внешний узел не найден.

Так что мне было интересно.Кто-нибудь знает о стабильном выпуске Scene Builder, в котором нет этой ошибки (и, желательно, других серьезных ошибок) для более поздней версии Java (8, 9 или, может быть, 10, если она еще не выпущена)?Я также хотел бы, чтобы был мастер установки, который даст мне exe-приложение вместо исполняемого jar для лучшей интеграции с моей IDE.Если этого не существует, что вы больше опытные люди Scene Builder посоветуете мне сделать?Должен ли я сделать все свои документы fxml без вложенных узлов и добавить их позже вручную?

Спасибо за любую помощь!

РЕДАКТИРОВАТЬ: Все исходные файлы можно найти здесь .Обратите внимание, что внешний контейнер - SliderVariable, а внутренний - InfoIcon.

1 Ответ

0 голосов
/ 23 мая 2018

Вы можете вкладывать два или более пользовательских элемента управления в один и тот же файл jar, и он будет отлично работать из вашей IDE или из командной строки.

Но если вы импортируете этот файл из Scene Builder, некоторые из пользовательскихэлемент управления может быть не импортирован, если они зависят от других.

Для этого есть причина, и, что самое приятное, есть простое решение.

Как импортируются пользовательские элементы управления?

Если вы посмотрите на исходный код Scene Builder , чтобы импортировать возможные пользовательские элементы управления банка, существует класс JarExplorer,у которого есть explore метод .

Этот метод в основном будет проходить через каждый класс в банке, выясняя, является ли этот класс возможным пользовательским компонентом, который должен быть добавлен в библиотеку пользователя..

В конце концов, как это работает, пытаясь создать объект FXML на основе этого класса:

 entryClass = classLoader.loadClass(className);
 instantiateWithFXMLLoader(entryClass, classLoader);

Если это удается, класс добавляется в коллекцию компонентов.

Why не удается импортировать вложенный настраиваемый элемент управления?

Так почему же не удается импортировать вложенный настраиваемый элемент управления, представляющий собой элемент управления с другим настраиваемым элементом управления в качестве зависимости?Причину этого можно найти в отладке Scene Builder и распечатке полученного исключения:

try {
    instantiateWithFXMLLoader(entryClass, classLoader);
} catch (RuntimeException | IOException x) {
    status = JarReportEntry.Status.CANNOT_INSTANTIATE;
    x.printStackTrace(); // <-- print exception
} catch (Error | ClassNotFoundException x) {
    status = JarReportEntry.Status.CANNOT_LOAD;
    x.printStackTrace(); // <-- print exception
}

Ведение журнала это действительно полезно при создании любого типа настраиваемого элемента управления.

Вв случае вложенного пользовательского элемента управления, если зависимость уже доступна в пути к классам, а под путем к классу я имею в виду все зависимости, загруженные Scene Builder заранее, проблем не будет.Но если он недоступен, FXMLLoader не сможет создать действительный экземпляр этого элемента управления.

Давайте попробуем ваш SliderVariable элемент управления.Если вы распечатаете исключение, вы увидите что-то вроде этого:

javafx.fxml.LoadException: 
    at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2579)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2425)
    at com.oracle.javafx.scenebuilder.kit.library.util.JarExplorer.instantiateWithFXMLLoader(JarExplorer.java:110)
... 9 more

Caused by: java.lang.RuntimeException: javafx.fxml.LoadException: 
    file:.../SliderVariable-1.0-SNAPSHOT-shaded!/com/coolcompany/slidervariable/SliderVariable.fxml
...
Caused by: java.lang.ClassNotFoundException: com.coolcompany.infoicon.InfoIcon
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at javafx.fxml.FXMLLoader.loadTypeForPackage(FXMLLoader.java:2916)
    at javafx.fxml.FXMLLoader.loadType(FXMLLoader.java:2905)
    at javafx.fxml.FXMLLoader.importClass(FXMLLoader.java:2846)
... 26 more

Таким образом, в основном это объясняет, почему вложенный элемент управления не импортируется: внутренний элемент управления не был доступен в пути к классам заранее.

Возможное решение

Очевидно, что вы можете объединить оба элемента управления по отдельности, сначала импортировать элемент управления InfoIcon, а затем просто импортировать элемент управления SliderVariable.Но это может быть проблематично, если вы хотите распределить эти элементы управления в одной зависимости.

Лучшее решение

Так как же сделать внутренний контроль доступным для внешнегово время выполнения, если оба находятся в одной банке?

Это делается путем передачи загрузчика классов этого внешнего класса управления в FXMLLoader.И это можно сделать, вызвав метод FXMLLoader::setClassLoader во внешнем элементе управления.

В вашем случае:

FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("SliderVariable.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);

// set FXMLLoader's classloader!
fxmlLoader.setClassLoader(getClass().getClassLoader());

try {
    fxmlLoader.load();
} catch (IOException exception) { }

Если вы попытаетесь снова, вы получите оба элемента управления доступными в качестве пользовательских компонентов.

Importing nested controls

...