Я поместил весь свой код JavaFX в исполняемый файл JAR. Там все внутри.
Когда я скомпилирую его с помощью Eclipse IDE, он работает, но когда я пытаюсь выполнить JAR-файл, я получаю сообщение об ошибке.
Caused by: javafx.fxml.LoadException:
file:/home/asus/program/JUSBPlotter/JUSBPlotter-0.0.1-SNAPSHOT-jar-with-dependencies.jar!/se/danielmartensson/fxml/front.fxml
Когда у меня есть этот код Java
Parent root = FXMLLoader.load(getClass().getResource("/se/danielmartensson/fxml/front.fxml"));
В файле FXML нет ничего плохого.
fx:controller = "se.danielmartensson.controller.Front"
Также я получаю ошибки, когда пытаюсь отобразить изображение в JavaFX.
Caused by: java.io.FileNotFoundException: file:/home/asus/program/JUSBPlotter/JUSBPlotter-0.0.1-SNAPSHOT-jar-with-dependencies.jar!/se/danielmartensson/pictures/computer.png (No such file or directory)
Когда у меня есть этот код Java:
FileInputStream picture1 = new FileInputStream(getClass().getResource("/se/danielmartensson/pictures/computer.png").getFile());
Вопрос: Как я могу указать Java правильный путь к файлу в JAR-файле?
Вопрос: Если .../computer.png
— это ресурс, почему вы пытаетесь прочитать его с FileInputStream
?
@JoséPeda хорошо. Я не звонил mvn compile
, потому что это не сработает для меня. Я получаю ошибки, такие как: Main.java:[5,26] package javafx.application does not exist
@Slaw, потому что я не знаю, как поступить иначе :)
Посмотрите разделы openjfx.io/openjfx-docs/#IDE-Intellij, Maven и узнайте, как вы можете использовать плагин javafx-maven-plugin
для компиляции и запуска вашего проекта. Как только вы заработаете, попробуйте плагин shadow/jar, чтобы получить свою толстую банку.
@JoséPeda хорошо! Компиляция работает сейчас. Но есть ли способ создать толстый JAR-файл и запустить его без модулей? Вот так sudo java --module-path = "/usr/share/openjfx/lib" --add-modules=javafx.controls,javafx.fxml -jar JUBSPlotter2-0.0.1-SNAPSHOT-jar-with-dependencies.jar
@JoséPeda Мне нужно создать модульный проект в maven?
Толстая банка не работает с модулями, все в пути к классам. Вы можете комбинировать плагин javafx-maven-plugin для компиляции и запуска, а также плагин jar/shade для создания толстой банки. Также, если у вас есть модульный проект (это не обязательно), вы можете использовать jlink (из плагина javafx-maven) для создания образа времени выполнения вместо толстой банки.
@JoséPeda Хорошо! Теперь было довольно много информации. Я хочу создать приложение, на которое мне нужно только нажать, а затем оно запустится. Для этого я не должен использовать maven-assembly-plugin
? Вместо этого я должен использовать mvn javafx:jlink
для создания исполняемого образа?
Посмотрите этот отвечать и не торопитесь его обрабатывать :)
@JoséPeda Похоже, мне нужно следовать руководству Modular по вашей URL-ссылке openjfx :)
@JoséPeda Привет! Я получил ошибку Could not find goal 'jlink' in plugin org.openjfx:javafx-maven-plugin:0.0.1
Это потому, что я запускаю OpenJDK 11?
Увеличьте версию плагина до 0.0.2
@JoséPeda Стремись к успеху! Это должно быть в руководстве, потому что 0.0.1 по умолчанию.
То есть в мануале указано JavaFX 12 и плагин 0.0.2, см. например этот рис.
@JoséPeda Хорошо. Спасибо. Когда я запускаю mvn javafx:jlink
и мой проект называется JUSBPlotter
, я ожидаю папку с именем JUSBPlotter
внутри папки target
, но не могу найти папки с именем JUSBPlotter
. Или это папка image
, которую я должен запустить?
@JoséPeda Теперь это работает. Я просто следую этому руководству, чтобы создать образ! github.com/openjfx/javafx-maven-плагин JavaFX великолепен!
Следует помнить, что ресурсы — это не то же самое, что файлы, несмотря на то, что они кажутся очень похожими, особенно перед упаковкой приложения. Когда вы упаковываете приложение, эти файлы ресурсов становятся записями в JAR-файле, который, хотя и может рассматриваться как файлы, не может быть доступен так же, как файлы. В частности, java.io.File
API не понимает, как читать эти записи. Однако вы можете получить доступ к этим записям через URL
, возвращаемый Class#getResource(String)
, или InputStream
, возвращаемый Class#getResourceAsStream(String)
. Обратите внимание, что последний в основном просто находит URL
и, если он существует, вызывает URL#openStream()
. Причина, по которой вы можете получить доступ к записям JAR (т.е. ресурсам) с помощью URL
, связана с JarURLConnection
и связанными классами; Я не буду вдаваться в подробности о том, как Java обрабатывает URL-адреса, поскольку это выходит за рамки этого ответа.
Теперь, поскольку вы пытаетесь отобразить изображение в JavaFX, я предполагаю, что вы используете класс Image
. Есть три основных способа сообщить Image
, где находится ресурс изображения.
Используйте Image#<init>(String)
, если URL-адрес аргумента не имеет схемы. В этом случае класс будет рассматривать URL-адрес как путь относительно корня пути к классам и попытается соответствующим образом получить доступ к изображению. По сути, аргумент — это тот же аргумент, который вы бы дали Class#getResource(String)
, за исключением того, что путь должен быть абсолютным (то есть не относительным ни к какому классу). Это поведение задокументировано классом Image
:
All URLs supported by
URL
can be passed to the constructor. If the passed string is not a valid URL, but a path instead, the Image is searched on the classpath in that case.
Примечание. Если вы используете модули, то при использовании этой опции в игру вступает инкапсуляция ресурсов. См. Ошибка GitHub № 441.
Используйте тот же конструктор, что и выше, но передайте действительный URL-адрес (т.е. он имеет схему). При использовании ресурса вы можете просто преобразовать URL
, возвращаемый Class#getResource(Sring)
, в String
, используя URL#toExternalForm()
.
Image image = new Image(getClass().getResource(...).toExternalForm());
Примечание. Вы также можете использовать URL#toString()
, который возвращает то же значение.
Используйте Image#<init>(InputStream)
. Здесь вы можете использовать Class#getResourceAsStream(String)
. Не забудьте закрыть InputStream
, когда закончите с этим.
try (InputStream is = getClass().getResourceAsStream(...)) {
Image image = new Image(is);
}
Все это предполагает, что ресурсы были правильно упакованы в ваш файл JAR, когда вы его создавали. Если это не так, сначала следуйте совету Хосе Переды в комментариях к вопросу.
Обратите внимание, что доступ к записям файла ZIP/JAR можно получить с помощью java.util.zip.*
API, java.util.jar.*
API или Java NIO ZipFileSystemProvider
. Каждый из них, особенно последний, позволяет вам получить доступ к записям ZIP/JAR-файла, аналогичного реальным файлам, потому что они разработаны специально для этого. Однако при использовании ресурсов в приложении вы должны придерживаться Class#getResource(String)
и связанных с ним методов.
Убедитесь, что ваш толстый файл jar также содержит ресурсы. Похоже, что их не хватает. Обычно это может произойти, если вы не запустили
mvn compile
, так как плагин компиляции также вызывает плагин ресурсов.