IntelliJ nie może rozpoznać JavaFX 11 z OpenJDK 11


83

Mam problem ze zrozumieniem przez IntellJ pakietów JavaFX. Z nowym projektem JavaFX, z OpenJDK 11, podczas próby zbudowania projektu IntelliJ nie może rozpoznać pakietów JavaFX.

Zaimportowałem openjfx:javafx-base-11z repozytorium Maven.

Przyjrzałem się innym pytaniom i wydaje się, że rozwiązania wahają się od sprawdzenia, czy kod bajtowy jest na właściwym poziomie (mój jest) i czy język projektu jest poprawny (mój jest).

Czy ktoś ma jakieś pomysły?

rys 1

rys 2

rys 3

Edytować:

Błąd:

wprowadź opis obrazu tutaj


czy możesz spróbować skompilować i uruchomić z terminala?
drowny

Będziesz musiał wymagać jego modułów w swoimmodule-info.java
Jacob G.

Myślę, że potrzebujesz tego artefaktu: mvnrepository.com/artifact/org.openjfx/javafx/11 podstawowy nie zawiera wszystkiego, co myślę.
Jorn Vernee

@JornVernee, gdy próbuję, pojawia się błąd. Edytowałem nim OP.
AlwaysNeedingHelp

1
Ktokolwiek ci to powiedział, prawdopodobnie się pomylił. Musisz utworzyć module-info.javaplik w folderze źródłowym wyraźnie wymagają Niezależnie od modułów JavaFX, że jesteś przy użyciu: requires javafx.controls;, requires javafx.graphics;, itd.
Jacob G.

Odpowiedzi:


134

Jak wspomniano w komentarzach, przewodnik startowy to miejsce, w którym można rozpocząć pracę z Javą 11 i JavaFX 11.

Kluczem do pracy tak, jak robiłeś to przed Java 11, jest zrozumienie, że:

  • JavaFX 11 nie jest już częścią JDK
  • Możesz go pobrać w różnych smakach, jako SDK lub jako zwykłe zależności (maven / gradle).
  • Będziesz musiał dołączyć go do ścieżki modułu swojego projektu, nawet jeśli Twój projekt nie jest modułowy.

Projekt JavaFX

Jeśli tworzysz zwykły domyślny projekt JavaFX w IntelliJ (bez Maven lub Gradle), sugeruję pobranie SDK stąd . Zauważ, że istnieją również jmody, ale w przypadku projektów niemodułowych preferowany jest pakiet SDK.

Oto proste kroki, aby uruchomić domyślny projekt:

  1. Utwórz projekt JavaFX
  2. Ustaw JDK 11 (wskaż lokalną wersję Java 11)
  3. Dodaj zestaw JavaFX 11 SDK jako bibliotekę. Adres URL może mieć postać /Users/<user>/Downloads/javafx-sdk-11/lib/. Gdy to zrobisz, zauważysz, że klasy JavaFX są teraz rozpoznawane w edytorze.

Projekt JavaFX 11

  1. Przed uruchomieniem domyślnego projektu wystarczy dodać je do opcji maszyny wirtualnej:

    --module-path /Users/<user>/Downloads/javafx-sdk-11/lib --add-modules=javafx.controls,javafx.fxml

  2. Biegać

Maven

Jeśli używasz Maven do tworzenia projektu, wykonaj następujące kroki:

  1. Utwórz projekt Maven z archetypem JavaFX
  2. Ustaw JDK 11 (wskaż lokalną wersję Java 11)
  3. Dodaj zależności JavaFX 11.

    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>11</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-fxml</artifactId>
            <version>11</version>
        </dependency>
    </dependencies>
    

Gdy to zrobisz, zauważysz, że klasy JavaFX są teraz rozpoznawane w edytorze.

Projekt JavaFX 11 Maven

Zauważysz, że Maven zarządza wymaganymi zależnościami za Ciebie: doda javafx.base i javafx.graphics dla javafx.controls, ale co najważniejsze, doda wymagany klasyfikator oparty na Twojej platformie. W moim przypadku Mac.

Dlatego twoje słoiki org.openjfx:javafx-controls:11puste , ponieważ istnieją trzy możliwe klasyfikatory (platformy Windows, Linux i Mac), które zawierają wszystkie klasy i natywną implementację.

Jeśli nadal chcesz przejść do repozytorium .m2 i pobrać z niego zależności ręcznie, upewnij się, że wybrałeś właściwy (na przykład .m2/repository/org/openjfx/javafx-controls/11/javafx-controls-11-mac.jar)

  1. Zastąp domyślne wtyczki Maven tymi z tego miejsca .

  2. Uruchom mvn compile javafx:runi powinno działać.

Podobnie działa również w przypadku projektów Gradle, jak szczegółowo wyjaśniono tutaj .

EDYTOWAĆ

Wspomniany przewodnik Pierwsze kroki zawiera zaktualizowaną dokumentację i przykładowe projekty dla IntelliJ:


1
Ścieżka jest czymś w rodzaju /Users/<user>/Downloads/javafx-sdk-11/lib/, zwróć uwagę na libfolder. To powinno zawierać wszystkie słoiki javafx
José Pereda

5
Jeśli ktoś ma problemy ze ścieżką modułu, w systemie Windows musi ona wyglądać mniej więcej tak: --module-path = "C: \ Path \ To \ Your \ JavaFX \ lib" --add-modules = javafx.controls, javafx .fxml, javafx.base, javafx.media, javafx.graphics, javafx.swing, javafx.web Zwróć uwagę na „=” i otaczające go cudzysłowy. To zadziałało dla mnie, podczas gdy inne podejście nie. Ponadto należy pamiętać, że parametr -jar YourJar.jar musi pojawić się ZA ścieżką modułu i opcjami add-modules.
Jalau,

4
Cześć @ JoséPereda. Od jakiegoś czasu zmagam się z tym przewodnikiem, ale tak naprawdę nie mogę zmusić IntelliJ do uruchomienia mojego kodu, nawet jeśli zrobiłem dokładnie to, co napisałeś. Nadal otrzymuję komunikat „Błąd: java: nie znaleziono modułu: javafx.fxml” i tak dalej. Jest jakaś szansa na prywatny czat, który pomoże mi rozwiązać ten problem? Dziękuję Ci.
Davide3i

1
@jalau dziękuję! cytaty faktycznie to zrobiły, powinieneś napisać to jako odpowiedź.
doskonały

2
Kiedy buduję dystrybucję dla przykładowego projektu dla Gradle, a następnie ją uruchamiam,
pojawia

10

Problem polegający na tym, że JavaFX nie jest już częścią JDK 11. Następujące rozwiązanie działa przy użyciu IntelliJ (nie próbowałem go z NetBeans):

  1. Dodaj bibliotekę globalną JavaFX jako zależność:

    Ustawienia -> Struktura projektu -> Moduł. W module przejdź do zakładki Zależności i kliknij znak „+” -> Biblioteka -> Java-> wybierz z listy JavaFX i kliknij Dodaj wybrane, a następnie Zastosuj ustawienia.

  2. Kliknij prawym przyciskiem myszy plik źródłowy (src) w projekcie JavaFX i utwórz nowy plik module-info.java . Wewnątrz pliku napisz następujący kod:

    module YourProjectName { 
        requires javafx.fxml;
        requires javafx.controls;
        requires javafx.graphics;
        opens sample;
    }
    

    Zapewniam, że te 2 kroki rozwiążą wszystkie problemy z JavaFX.

Odniesienie: Istnieje samouczek You Tube przygotowany przez kanał Learn Programming, który wyjaśni wszystkie powyższe szczegóły w zaledwie 5 minut. Polecam również obejrzenie go w celu rozwiązania problemu: https://www.youtube.com/watch?v=WtOgoomDewo


8

Żadne z powyższych nie działało dla mnie. Spędziłem zbyt dużo czasu na usuwaniu innych błędów, które się pojawiły. Uważam, że jest to najłatwiejszy i najlepszy sposób.

Działa to również w przypadku uzyskiwania JavaFx na Jdk 11, 12 i OpenJdk12!

  • Wideo przedstawia pobieranie JavaFx Sdk
  • Jak ustawić go jako bibliotekę globalną
  • Ustaw plik module-info.java (wolę dolny)

module thisIsTheNameOfYourProject {
    requires javafx.fxml;
    requires javafx.controls;
    requires javafx.graphics;
    opens sample;
}

Całość zajęła mi tylko 5 min !!!


Ustaw go jako bibliotekę globalną, która została przeniesiona w 2019 r. Czy możesz wskazać, gdzie to się teraz znajduje?
Michael S.

5

Szybkie podsumowanie, możesz:

  1. Dołącz moduły JavaFX za pośrednictwem --module-pathi--add-modules jak w odpowiedzi José.

    LUB

  2. Po dodaniu bibliotek JavaFX do projektu (ręcznie lub za pomocą importu maven / gradle) dodaj module-info.javaplik podobny do podanego w tej odpowiedzi. (Zwróć uwagę, że to rozwiązanie sprawia, że ​​Twoja aplikacja jest modułowa, więc jeśli używasz innych bibliotek, będziesz musiał również dodać instrukcje, aby wymagać ich modułów w module-info.javapliku).


Ta odpowiedź jest uzupełnieniem odpowiedzi Jose.

Sytuacja jest następująca:

  1. Używasz najnowszej wersji Java, np. 13.
  2. Masz aplikację JavaFX jako projekt Maven.
  3. W swoim projekcie Maven masz skonfigurowaną wtyczkę JavaFX i ustawienia zależności JavaFX zgodnie z odpowiedzią Jose.
  4. Wchodzisz do kodu źródłowego swojej głównej klasy, która rozszerza Application, klikasz go prawym przyciskiem myszy i próbujesz go uruchomić.
  5. Masz IllegalAccessErrorobejmujące moduł „nienazwany” podczas próby uruchomienia aplikacji.

Fragment śledzenia stosu generującego plik IllegalAccessError podczas próby uruchomienia aplikacji JavaFX z Intellij Idea:

Exception in Application start method
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)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
    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)
    at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
Caused by: java.lang.RuntimeException: Exception in Application start method
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
    at java.base/java.lang.Thread.run(Thread.java:830)
Caused by: java.lang.IllegalAccessError: class com.sun.javafx.fxml.FXMLLoaderHelper (in unnamed module @0x45069d0e) cannot access class com.sun.javafx.util.Utils (in module javafx.graphics) because module javafx.graphics does not export com.sun.javafx.util to unnamed module @0x45069d0e
    at com.sun.javafx.fxml.FXMLLoaderHelper.<clinit>(FXMLLoaderHelper.java:38)
    at javafx.fxml.FXMLLoader.<clinit>(FXMLLoader.java:2056)
    at org.jewelsea.demo.javafx.springboot.Main.start(Main.java:13)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
Exception running application org.jewelsea.demo.javafx.springboot.Main

OK, teraz utknęłaś i nie masz pojęcia, co się dzieje.

Co się właściwie wydarzyło, to:

  1. Maven pomyślnie pobrał zależności JavaFX dla Twojej aplikacji, więc nie musisz oddzielnie pobierać zależności ani instalować pakietu JavaFX SDK lub dystrybucji modułów ani niczego podobnego.
  2. Idea z powodzeniem zaimportowała moduły jako zależności do twojego projektu, więc wszystko kompiluje się dobrze, a zakończenie kodu i wszystko działa dobrze.

Więc wydaje się, że wszystko powinno być w porządku. ALE, gdy uruchamiasz aplikację, kod w modułach JavaFX kończy się niepowodzeniem podczas próby użycia odbicia w celu utworzenia instancji Twojej klasy aplikacji (podczas wywoływania uruchomienia) i klas kontrolera FXML (podczas ładowania FXML). Bez pewnej pomocy takie wykorzystanie refleksji może w niektórych przypadkach zawieść, generując niejasnośćIllegalAccessError . Wynika to z funkcji zabezpieczeń systemu modułu Java, która nie pozwala kodowi z innych modułów na używanie odbicia na twoich klasach, chyba że wyraźnie na to zezwolisz (a program uruchamiający aplikacje JavaFX i FXMLLoader wymagają odzwierciedlenia w ich bieżącej implementacji, aby mogły działać prawidłowo).

W tym miejscu module-info.javapojawiają się niektóre inne odpowiedzi na to pytanie, które zawierają odniesienie .

Zróbmy więc szybki kurs dotyczący modułów Java:

Kluczowa część jest taka:

4.9. Otwiera

Jeśli musimy zezwolić na odbicie typów prywatnych, ale nie chcemy, aby cały nasz kod był ujawniany, możemy użyć dyrektywy opens, aby ujawnić określone pakiety.

Pamiętaj jednak, że to otworzy pakiet na cały świat, więc upewnij się, że tego chcesz:

module my.module { opens com.my.package; }

Więc być może nie chcesz otwierać swojego pakietu na cały świat, możesz zrobić:

4.10. Otwiera… do

Okay, więc czasami refleksja jest świetna, ale nadal chcemy jak największego bezpieczeństwa dzięki hermetyzacji. Możemy selektywnie otwierać nasze pakiety na wstępnie zatwierdzoną listę modułów, w tym przypadku za pomocą dyrektywy opens… to:

moduł my.module {otwiera com.my.package na moduleOne, moduleTwo itd .; }

W rezultacie tworzysz klasę src / main / java / module-info.java, która wygląda następująco:

module org.jewelsea.demo.javafx.springboot {
    requires javafx.fxml;
    requires javafx.controls;
    requires javafx.graphics;
    opens org.jewelsea.demo.javafx.springboot to javafx.graphics,javafx.fxml;
}

Gdzie org.jewelsea.demo.javafx.springbootjest nazwą pakietu zawierającego klasę aplikacji JavaFX i klasy kontrolera JavaFX (zastąp ją odpowiednią nazwą pakietu dla aplikacji). To informuje środowisko wykonawcze Java, że ​​jest OK dla klas w javafx.graphicsijavafx.fxml wywołać refleksję na temat klas w org.jewelsea.demo.javafx.springbootpakiecie . Gdy to zrobisz, a aplikacja zostanie skompilowana i ponownie uruchomiona, wszystko będzie działać dobrze, a IllegalAccessErrorwygenerowane przez JavaFX odbicie nie będzie już występować.

Ale co, jeśli nie chcesz tworzyć pliku module-info.java

Jeśli zamiast używać przycisku Uruchom na górnym pasku narzędzi IDE do bezpośredniego uruchamiania klasy aplikacji, zamiast tego:

  1. Poszedłem do okna Mavena z boku IDE.
  2. Wybierz cel wtyczki javafx maven javafx.run .
  3. Kliknął prawym przyciskiem myszy i wybrał albo Run Maven Buildalbo Debug....

Wtedy aplikacja będzie działać bez module-info.javapliku. Wydaje mi się, że dzieje się tak dlatego, że wtyczka maven jest wystarczająco inteligentna, aby dynamicznie włączać pewne ustawienia, które pozwalają na odzwierciedlenie aplikacji przez klasy JavaFX nawet bez module-info.javapliku, chociaż nie wiem, jak to się dzieje.

Aby przenieść to ustawienie do przycisku Uruchom na górnym pasku narzędzi, kliknij prawym przyciskiem myszy javafx.runcel Mavena i wybierz opcję Create Run/Debug Configurationdla celu. Następnie możesz po prostu wybrać Uruchom z górnego paska narzędzi, aby wykonać cel Mavena.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.