JavaFXライブラリのインストール¶
はじめに¶
Java SE 11以降、JavaFXはライブラリとして別途インストールするようになりました。本ページは、Java SE 11以降でJavaFXライブラリを利用した開発をするためのインストール作業を記述します。
JavaFXは、OSネイティブなライブラリを含むため、OS別にリリースされたライブラリを入手しインストールします。
JavaFX同梱のOpenJDKもある¶
OpenJDKのバイナリはいくつかの組織から提供されており、中にはJavaFXを同梱したものがあります。これを使えばJavaFXを別途インストールする必要はなくなります。
OpenJDKに記載。
Windows用のJDKとJavaFXのネイティブビルドの差異が懸念¶
Windows版では、OpenJDKのバイナリが使用するVC++ランタイムバージョンとJavaFXライブラリのバイナリが使用するVC++ランタイムバージョンが違うと組み合わせたときの動作が大丈夫かなという心配があります。原則、OpenJDKをビルドしたVisual C++バージョンとJavaFXをビルドしたVisual C++バージョンがメジャーバージョンで一致している必要があります。ただ、次の記事によれば、Visual C++ 2015以降であればメジャーバージョンが異なっても互換性があるようです。
https://docs.microsoft.com/ja-jp/cpp/porting/binary-compat-2015-2017?view=msvc-160
入手¶
JavaFXは、現在次のリリースがあります。
- OpenJFXのダウンロードサイト
- Gluon社のダウンロードサイト
- mavenリポジトリ
OpenJFXのダウンロードサイトから入手¶
OpenJFXサイト(以下URL)からビルド済みのJavaFXライブラリをダウンロードします。
https://openjfx.io/
現時点(2018-10-11)では、ダウンロードのリンク先がGluon社のJavaFXサイトとなっており、そこからOS毎のライブラリをダウンロードするようになっています。
Gluon社のダウンロードサイトから入手¶
https://gluonhq.com/products/javafx/
各OS毎(Windows、Mac、Linux)に、SDKとjmodsと2つのアーカイブが提供されます。
SDKには、OSネイティブのライブラリ、JARファイルが含まれています。
jmodsには、Javaモジュールファイル(jmod)が含まれています。jmodファイルはコンパイル・リンク用に使うためのもので、jmodファイル内にOSネイティブのライブラリも含まれています。jmodファイルは実行時には使えません。
アプリケーション実行用のイメージ(アプリケーションモジュールとその実行に必要とするJavaモジュールを抜粋したアプリケーション実行環境)を作成しないのであれば前者のSDKだけ入手すれば十分です。イメージを作成する場合はSDKに加えて後者のjmodsも入手します。
Windows版の入手とインストール¶
JavaFXライブラリを、C:\Program Files\Java\JavaFX
の下に置くこととします。
Gluon社のダウンロードサイトから次をダウンロードします。
次は、JavaFX 11.0.2の場合です。
名称 | ファイル名 |
---|---|
JavaFX Windows SDK | openjfx-11.0.2_windows-x64_bin-sdk.zip |
JavaFX Windows jmods | openjfx-11.0.2_windows-x64_bin-jmods.zip |
各zipファイルを、C:\Program Fils\Java\JavaFX
の下に展開します。
C:\Program Files\Java\JavaFX +-- javafx-sdk-11.0.2 | +-- bin | | +-- *.dll | +-- legal | +-- lib | +-- *.jar +-- javafx-jmods-11.0.2 +-- *.jmod
JavaFX APIドキュメントの入手¶
JavaFX のAPIドキュメントはオンラインでは次のURLから[Documentation]リンクを辿って参照できます。
https://openjfx.io/
オフラインで利用できるようダウンロードするには、次のGithubリポジトリからコンテンツをダウンロードします。
- API Javadoc
https://github.com/openjfx/javadoc - OpenJFX ドキュメント
https://github.com/openjfx/openjfx-docs
上述URLをブラウザで開き、[Clone or download] > [Download ZIP] でダウンロードできます。
動作確認¶
ライブラリをインストールしたら、動作確認のため簡単なプログラムをビルド・実行します。
空白のウィンドウを表示するプログラム¶
作業ディレクトリの作成¶
作業ディレクトリを用意し、ソースコードを置くディレクトリ、コンパイル結果を置くディレクトリを作ります。
SimpleApp +-- build +-- src +-- com.torutk.simplefx <-- モジュール名に一致する名前 +-- com <-- パッケージ名に基づくディレクトリ名 +-- torutk <-- パッケージ名に基づくディレクトリ名 +-- simplefx <-- パッケージ名に基づくディレクトリ名
ソースファイルを作成¶
- src\com.torutk.simplefx\com\torutk\simplefx\SimpleApp.java
package com.torutk.simplefx; import javafx.application.Application; import javafx.stage.Stage; public class SimpleApp extends Application { @Override public void start(Stage primaryStage) { primaryStage.show(); } }
モジュール記述子を作成¶
- src\com.torutk.simplefx\module-info.java
module hellofx { requires javafx.controls; // (1) opens com.torutk.hello to javafx.graphics; // (2) }
- (1)
今回のソースコードから利用するJavaFXのAPIは、javafx.graphicsモジュールに含まれますが、アプリケーションからは通常はjavafx.controlsモジュールへの依存を定義します。javafx.controlsは、javafx.graphicsへの依存(推移的依存)を持つので、アプリケーションプログラム側のモジュール記述子にはjavafx.controlsモジュールへの依存を明示的に定義することでjavafx.graphicsへの依存も定義され、その中のクラスを利用できるようになります。 - (2)
アプリケーションプログラム側で定義したJavaFXのApplication派生クラスは、実行時にJavaFXライブラリ側でリフレクションを使ってインスタンス化されます。そのため、実行時にJavaFXライブラリ(の中のjavafx.graphicsモジュール)からアプリケーションプログラム側のApplication派生クラスのパッケージに対してリフレクションを許可するopens指定をモジュール記述子に定義します。
ソースファイルの構成¶
この時点で作業ディレクトリには次の様にファイルが置かれます。
SimpleApp +-- build +-- src +-- com.torutk.simplefx +-- module-info.java +-- com +-- torutk +-- simplefx +-- SimpleApp.java
コンパイル¶
D:\work\SimpleApp> javac -d build -p "C:\Program Files\Java\JavaFX\javafx-sdk-11.0.2\lib" --module-source-path src -m com.torutk.simplefx D:\work\SimpleApp>
- -dオプションでコンパイル結果出力先ディレクトリを指定
- -pオプションでJavaFXライブラリ(JARファイルまたはjmodファイル)が収められた場所を指定
-pは、--module-pathの省略形 - --module-source-pathでコンパイルするモジュールのソースファイルが収められた場所を指定
- -mオプションでコンパイルするモジュールを指定
-mは、--module-nameの省略形
コンパイル結果は次のようになります。
SimpleApp +-- build +-- com.torutk.simplefx +-- module-info.class +-- com +-- torutk +-- simplefx +-- SimpleApp.class
コンパイル結果の実行¶
D:\work\SimpleApp> java -p build;"C:\Program Files\Java\JavaFX\javafx-sdk-11.0.2\lib" -m com.torutk.simplefx/com.torutk.simplefx.SimpleApp
モジュールJARファイルの作成¶
先のビルド結果から、モジュールJARファイルを生成します。
まず、モジュールJARファイルを格納するディレクトリを作成しておきます。
SimpleApp +-- build +-- mods
D:\work\SimpleApp> jar cfe build\mods\com.torutk.simplefx.jar com.torutk.simplefx.SimpleApp -C build\com.torutk.simplefx .
- cfオプションで新たにJARファイルを指定したパスで生成
cオプションは、--createオプションの超短縮形(UNIXのtarコマンドオプション流儀)です。
fオプションは、--fileオプションの超短縮形(同上)です。 - eオプションでエントリポイントのクラスを指定
eオプションは、--main-classオプションの超短縮形です。
モジュールJARファイルの実行¶
D:\work\SimpleApp> java -p build\mods;"C:\Program Files\Java\JavaFX\javafx-sdk-11.0.2\lib" -m com.torutk.simplefx
モジュールJARファイルの生成時にエントリポイントを指定したので、-mオプションではモジュール名だけ指定します。
リンク(アプリケーション実行用のイメージ作成)¶
アプリケーションを実行するのに必要なモジュールだけを抜粋したJava実行環境を作成します。
D:\work\SimpleApp> jlink -p build;"C:\Program Files\Java\JavaFX\javafx-jmods-11.0.2" --add-modules com.torutk.simplefx --launcher simplefx=com.torutk.simplefx/com.torutk.simplefx.SimpleApp --output simplefx-image
少し時間がかかりますが、成功すると--outputオプションで指定したディレクトリの下に、アプリケーションプログラムとその実行に必要なJavaの実行環境が生成されます。ディレクトリ構造を次に示します。
SimpleApp +-- simplefx-image +-- lib | +-- security | +-- server +-- conf | +-- security | +-- policy | +-- limited | +-- unlimited +-- include | +-- win32 +-- bin | +-- server +-- legal
binディレクトリの下に、jlinkの--launcherオプションで指定した起動スクリプト(simplefxおよびsimplefx.bat)が生成されます。これを実行するとアプリケーションが起動します。
D:\work\SimpeApp> simplefx-image\bin\simplefx
FXMLで定義した画面(テキストメッセージ)を表示するプログラム¶
作業ディレクトリの作成¶
作業ディレクトリを用意し、ソースコードを置くディレクトリ、コンパイル結果を置くディレクトリを作ります。
SimpleFxmlApp +-- build +-- src +-- com.torutk.simplefx <-- モジュール名に一致する名前 +-- com <-- パッケージ名に基づくディレクトリ名 +-- torutk <-- パッケージ名に基づくディレクトリ名 +-- simplefx <-- パッケージ名に基づくディレクトリ名
ソースファイルを作成¶
JavaFXアプリケーションクラス¶
- src\com.torutk.simplefx\com\torutk\simplefx\SimpleFxmlApp.java
package com.torutk.simplefx; import javafx.application.Application; import javafx.stage.Stage; public class SimpleFxmlApp extends Application { @Override public void start(Stage primaryStage) { var root = FXMLLoader.load(getClass().getResource("SimpleView.fxml")); primaryStage.setScene(new Scene(root)); primaryStage.show(); } }
FXMLファイル¶
- src\com.torutk.simplefx\com\torutk\simplefx\SimpleView.fxml
<?import javafx.scene.layout.GridPane?> <?import javafx.scene.control.Label?> <GridPane xmlns:fx="http://javafx.com/fxml" alignment="center"> <Label text="Hello, JavaFX" /> </GridPane>
モジュール記述子を作成¶
- src\com.torutk.simplefx\module-info.java
module com.torutk.simplefx { requires javafx.controls; requires javafx.fxml; opens com.torutk.simplefx to javafx.graphics, javafx.fxml; }
ソースファイルの構成¶
この時点で作業ディレクトリには次の様にファイルが置かれます。
SimpleFxmlApp +-- build +-- src +-- com.torutk.simplefx +-- module-info.java +-- com +-- torutk +-- simplefx +-- SimpleFxmlApp.java +-- SimpleView.fxml
コンパイル¶
D:\work\SimpleFxmlApp> javac -d build -p "C:\Program Files\Java\JavaFX\javafx-sdk-11.0.2\lib" --module-source-path src -m com.torutk.simplefx D:\work\SimpleFxmlApp>
FXMLファイルを、アプリケーションクラスと同じ場所にコピーします。
D:\work\SimpleFxmlApp> copy src\com.torutk.simplefx\com\torutk\simplefx\SimpleView.fxml build\com.torutk.simplefx\com\torutk\ximplefx\ 1 個のファイルをコピーしました。 D:\work\SimpleFxmlApp>
コンパイル結果の実行¶
D:\work\SimpleFxmlApp> java -p build;"C:\Program Files\Java\JavaFX\javafx-sdk-11.0.2\lib" -m com.torutk.simplefx/com.torutk.simplefx.SimpleFxmlApp
トラブルシューティング¶
Application派生クラスで実行時例外(InvocationTargetException)¶
モジュール記述子に、javafx.graphicsモジュールからApplication派生クラスのパッケージに対するリフレクションを許可するopens定義を記述しなかった場合、実行時に次のエラーが発生します。
Exception in Application constructor Exception in thread "main" 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:566) at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051) Caused by: java.lang.RuntimeException: Unable to construct Application instance: class com.torutk.hello.Hello at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:890) at javafx.graphics/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.IllegalAccessException: class com.sun.javafx.application.LauncherImpl (in module javafx.graphics) cannot access class com.torutk.hello.Hello (in module hellofx) because module hellofx does not export com.torutk.hello to module javafx.graphics at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:361) at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:591) at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481) at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$8(LauncherImpl.java:802) 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(Native Method) 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) at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method) at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174) ... 1 more
javafx.graphicsモジュール(Applicationクラスを含むモジュール)が、Application派生クラスへリフレクションを使ったアクセスをする際にエラーとなっています。
モジュール記述子でアプリケーションのモジュールを公開する必要があります。
次の記述を追加します。
opens com.torutk.hello to javafx.graphics;
jlinkで生成したイメージの実行時例外¶
jlinkで実行イメージを生成する際に、JavaFXのSDKを指定した場合、つまりモジュールJARファイルのある場所を指定した場合、次のエラーが実行時に発生しました。
D:\work\hello> hellofx-image\bin\hello Graphics Device initialization failed for : d3d, sw Error initializing QuantumRenderer: no suitable pipeline found java.lang.RuntimeException: java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found at javafx.graphics/com.sun.javafx.tk.quantum.QuantumRenderer.getInstance(QuantumRenderer.java:280) at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.init(QuantumToolkit.java:222) at javafx.graphics/com.sun.javafx.tk.Toolkit.getToolkit(Toolkit.java:260) at javafx.graphics/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:267) at javafx.graphics/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:158) at javafx.graphics/com.sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.java:658) at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:409) 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:566) at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051) Caused by: java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found at javafx.graphics/com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.init(QuantumRenderer.java:94) at javafx.graphics/com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:124) at java.base/java.lang.Thread.run(Thread.java:834) Exception in thread "main" 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:566) at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051) Caused by: java.lang.RuntimeException: No toolkit found at javafx.graphics/com.sun.javafx.tk.Toolkit.getToolkit(Toolkit.java:272) at javafx.graphics/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:267) at javafx.graphics/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:158) at javafx.graphics/com.sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.java:658) at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:409) at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363) ... 5 more
JARファイルのある場所を指定して実行イメージを生成すると、ネイティブライブラリが展開されません。
解決には、jmodファイルのある場所を指定する必要があります。jmodファイルにはネイティブライブラリが含まれているので、生成された実行イメージにはネイティブライブラリが含まれます。
FXMLファイル読み込みの実行時例外¶
FXMLファイルをコピーし忘れた場合に発生します。
Exception in Application start method Exception in thread "main" 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:566) 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:834) Caused by: java.lang.NullPointerException: Location is required. at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3230) at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3194) at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3163) at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3136) at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3113) at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:3106) at com.torutk.simplefx/com.torutk.simplefx.SimpleFxmlApp.start(SimpleFxmlApp.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(Native Method) 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) at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method) at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174) ... 1 more