JavaFX Application erstellen funktioniert nicht (IntelliJ)?
Ich sitze nun seit über 4 Stunden da dran und ich habe keine Lust mehr zu recherchieren...
Wichtig zu erwähnen ist aber, dass das Program in der IDE funktioniert, aber außerhalb:
Fehler: Hauptklasse application.Main konnte nicht gefunden oder geladen werden
Ursache: java.lang.NoClassDefFoundError: javafx/application/Application
oder
Fehler: Zum Ausführen dieser Anwendung benötigte JavaFX-Runtime-Komponenten fehlen
nicht. Je nach dem, ob ich JAR oder JavaFX Application bei Artifacts verwende, kommt eines der Fehlermeldungen. Bei JavaFX Application steht bei Artifacts unten aber auch
Can't build artifacts - fx:deploy is not available in this JDK
, wenn ich die SDK 17.0.1 verwende und beim Build:
Java FX Packager: Unable to build JavaFX artifact. 'Application class' should be specified in artifact's settings.
Was ich versucht habe:
- Bei Projects habe ich mehrere SDKs ausprobiert
- In Run > Edit Configurations habe ich das Nötige mit dem --module-path Quatsch gemacht < hier habe ich javafx-sdk-17.0.1 und javafx-sdk-15.0.1 genutzt
- Bei Project Structure > Artifacts habe ich sowohl JAR und JavaFX Application ausprobiert
Welche ganzen Java-Versionen ich auf dem PC installiert habe:
1 Antwort
Can't build artifacts - fx:deploy is not available in this JDK
Der Task fx:deploy rührt noch vom Java Packager her, der für JDK-Versionen vor 9 benutzt werden konnte, um JavaFX-Applikationen zu bauen. Für spätere JDK-Versionen brauchst du ein 3rd-Party-Tool wie jpackage.
Da ich allerdings annehme, dass du in IntelliJ auch Gradle nutzt, dürfte es auch so gehen:
1) In der build.gradle führst du alle JavaFX-Dependencies auf, die du benötigst.
implementation 'org.openjfx:javafx:<Version>'
implementation 'org.openjfx:javafx-base:<Version>'
implementation 'org.openjfx:javafx-graphics:<Version>'
implementation 'org.openjfx:javafx-controls:<Version>'
implementation 'org.openjfx:javafx-fxml:<Version>'
implementation 'org.openjfx:javafx-media:<Version>'
// ...
Den <Version>-Platzhalter ersetzt du natürlich mit der Versionsnummer, die du verwendest. Welche Dependencies es so für JavaFX gibt, kannst du hier nachschauen. Wenn du einen Eintrag auswählst (und dazu die Version auf der Folgeseite), kannst du dir je Buildtool (Maven/Gradle/Ivy/...) das Snippet für die Buildkonfiguration anschauen (Beispiel).
2) Erstelle eine neue Klasse (die nicht von Application erbt), die folgend als Main Class agiert. Sie beinhaltet also eine main-Methode, in der die main-Methode deiner Application-Klasse aufgerufen wird.
In der build.gradle gibst du sie folglicherweise (für das Manifest) auch als Main Class an:
jar {
manifest {
attributes('Main-Class': '<YourMainClass>')
}
from {
configurations.runtimeClasspath.collect {
it.isDirectory() ? it : zipTree(it)
}
}
}
So wie ich das sehe, hast du das nicht.
Ich schildere einmal eine Schritt-für-Schritt-Anleitung. Dafür nutze ich IntelliJ Community 2021.2.3 mit Gradle sowie Amazon Corretto JDK 16.
1) Gradle Java-Projekt anlegen und Namen festlegen. Ich habe das Projekt buildjavafxtest genannt, so lautet auch die ArticleID. Die GroupID habe ich bei org.example belassen.
2) Unter src/main/java habe ich ein neues Package angelegt: com.example. Dieses beinhaltet dann drei Dateien:
Main.java
package com.example;
public class Main {
public static void main(String[] args) {
MainApp.main(args);
}
}
MainApp.java: Mit deinem Code, die einzigen Änderungen sind der Package-Name, der Klassenname und der Pfad zur FXML.
package com.example;
// ...
public class MainApp extends Application {
//...
FXMLLoader
.load(getClass()
.getClassLoader()
.getResource("com.example/Main.fxml"));
// ...
MainController.java
package com.example;
public class MainController {
}
3) Unter resources/com.example (ein neuer Ordner) liegt die Main.fxml. Ich denke, deren Inhalt kann ich auslassen. Der ist ziemlich irrelevant.
4) IntelliJ wird sich bei diesem Zustand natürlich noch ziemlich aufregen, da es verschiedene Symbole nicht aufösen kann. Nichtsdestotrotz habe ich erst einmal die module-info.java in src/main/java erstellt.
module buildjavafxtest.main {
requires javafx.controls;
requires javafx.fxml;
exports com.example;
}
Zum einen werden die zwei wichtigsten JavaFX-Module angefordert (evt. musst du für dein Projekt noch weitere ergänzen) und zum anderen der Packagepfad für die bisher angelegten Klassen exportiert.
5) Die build.gradle:
plugins {
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.10'
id 'org.beryx.jlink' version '2.12.0'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
javafx {
version = "15"
modules = [ 'javafx.controls', 'javafx.fxml' ]
}
jlink {
options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
launcher {
name = 'buildjavafxtest'
}
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
}
test {
useJUnitPlatform()
}
jar {
manifest {
attributes "Main-Class": "com.example.Main"
}
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
Die besteht aus einem zusammenkopierten Mix aus der Anleitung auf OpenJFX (Modular with Gradle), der Standardvorgabe von IntelliJ und dem, was ich schon oben schrieb.
Die Dependencies brauchen (so wie ich es oben schrieb) nicht aufgelistet werden. JLink ist dazu da, dir alle notwendigen Module zu einem Runtime Image zusammenzupacken.
Mein Zusatz
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
hat dabei folgendes Bewandnis: Beim Building werden unterschiedliche module-info-Dateien (z.B. aus JavaFX) entweder in ein Verzeichnis gepackt (INCLUDE) oder nur der erste Fund (EXCLUDE). Der Buildtask kann dies nicht allein entscheiden, deshalb muss eine Strategie vorgegeben werden.
Wichtig ist vor allem der Kniff, den ich schon in meiner Antwort erwähnte: Lege dir eine Stellvertreterklasse mit Einstiegspunkt an und setze diese auch als Startpunkt im Manifest. Wenn du das nicht tust, bekommst du deine Fehlermeldung.
6) Nach Aktualisierung der build.gradle (Ctrl + Shift + O) sollten die Fehler verschwinden, die dir in MainApp zuvor noch um die Ohren geflogen sind. Die Anwendung kann gebaut werden.
7) Im Gradle-Dialog (kann über die Leiste am rechten Fensterrand aufgeklappt werden) gibt es unter Tasks/build den Eintrag jar. Ein Doppelklick darauf und der Build deiner JAR sollte starten und ebenso erfolgreich enden.
8) Die fertige JAR-Datei befindet sich im Projektordner unter build/libs. Du kannst sie über die Konsole starten.
cd "your path to libs folder ..."
java -jar buildjavafxtest-1.0-SNAPSHOT.jar
Bei mir öffnet sich daraufhin, wie erwartet, ein Fenster mit, in meinem Fall, einem Label mit Text.
Ich danke Dir wirklich sehr und Deine Schritte werde ich in Zukunft versuchen, besser zu verstehen.
Jetzt ist aber das Lustige, dass diese Antwort hier von Dir einen anderen Fehler von mir behoben hat und somit jetzt alles funktioniert. Ich habe mich gerade etwas von IntelliJ und mir veräppelt gefühlt.
Guten Abend nochmal,
ich habe Deine Tipps angewandt, jedoch komme ich an der Fehlermeldung
nicht weiter. Diese Fehlermeldung kommt auch nur, wenn ich das Testprogramm exportiert habe und mit der Eingabeaufforderung ausführe.
Da ich immer nur den gleichen Lösungsweg mit "--module-path "C:\Users\..." in Run > Edit Configurations finde, dieser mich aber nicht weiterbringt, weil es ja in der IDE funktioniert, weiß ich mir nach tagelanger Fehlersuche nicht mehr zu helfen.
Vielleicht kannst Du da nochmal ein Auge drauf werfen 😅 Ich habe extra ein neues Projekt erstellt, um Fehler zu vermeiden.
Main | MANIFEST | build.gradle
Ich danke Dir nochmal vielmals für Deine Geduld.