JavaFXでプレローダの表示
はじめに
「javafx.application.Preloader」は、「javafx.application.Application」を継承しています。
そのため、自分のApplication本体とプレローダ用のアプリケーションを用意します。
JavaFXのアプリケーションは、起動フローとして次のようになっており、Preloaderクラスに現在どの段階か通知して連携します。
- JavaVMの起動。クラスファイルなどをメモリ上にロードします。
- JARファイルなどのダウンロード。(JNLP専用)
- 「StateChangeNotification.Type.BEFORE_LOAD」で、Preloaderに通知されます。
- Application#init()メソッドの実行。
- 「StateChangeNotification.Type.BEFORE_INIT」で、Preloaderに通知されます。
- Appliction#start()メソッドの実行。
- 「StateChangeNotification.Type.BEFORE_START」で、Preloaderに通知されます。
プレローダは、本体のApplicationとは別なApplicationなので、「MANIFEST.MF」ファイルの項目「JavaFX-Preloader-Class」で指定する必要があります。
そのため、JavaFX用のAntタスクを利用してパッケージングする必要があります。
- プレローダのサンプルや流れ、などは下記の公式サイト参照してください。
- Antタスクによるパッケージングは下記のサイトを参照してくだし。
NetBeansを使うと画面で簡単にできますが、ここではAntタスクを使った方法を説明します。
JavaFXの公式サイトでは、Preloader用とプログラム本体が別々なjarになっていますが、ここでは同じjarにあることを前提とします。
Preloaderの作成
Preloaderクラスを作成します。ここでは、最もシンプル形式にします。
凝ったものにしたい場合などは、公式サイトにサンプルが載っています。
import javafx.application.Preloader; import javafx.scene.Scene; import javafx.scene.control.ProgressBar; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; /** * もっともシンプルなプレローダ */ public class FirstPreloader extends Preloader { ProgressBar bar; Stage stage; private Scene createPreloaderScene() { bar = new ProgressBar(); BorderPane p = new BorderPane(); p.setCenter(bar); return new Scene(p, 300, 150); } @Override public void start(Stage stage) throws Exception { this.stage = stage; stage.setScene(createPreloaderScene()); stage.show(); } @Override public void handleProgressNotification(ProgressNotification pn) { bar.setProgress(pn.getProgress()); } @Override public void handleStateChangeNotification(StateChangeNotification evt) { if (evt.getType() == StateChangeNotification.Type.BEFORE_START) { // Application#start()の実行まえにプレローダを閉じる stage.hide(); } } }
アプリケーション本体
特に凝ったことをしなければ、initメソッドやstartメソッドが呼ばれるときに自動的にPreloaderに通知されるため、
何もする必要はありません。
JavaFXのAntタスクの設定
プレローダを指定する際には、要素
<?xml version="1.0" encoding="UTF-8"?> <!-- =============================================== JavaFXのパッケージングをするAntXMLファイル ====================================================--> <project name="sample-app" basedir="." default="jfx-package" xmlns:fx="javafx:com.sun.javafx.tools.ant"> <!-- JavaFXのアプリケーション用のAnt用のjarファイルのパスの取得 --> <property environment="env" /> <property name="javafx.tools.ant.jar" value="${env.JAVA_HOME}/lib/ant-javafx.jar" /> <!-- コンパイル済みのclassファイルの格納場所:mavenの形式 --> <property name="dest" location="target/classes" /> <!-- 実行可能な Jar ファイルが作成されるフォルダ:mavenの形式 --> <property name="jardest" location="target" /> <!-- アプリケーションの設定 --> <property name="app.vendor" value="javafx.sample" /> <!-- 実行可能 Jar ファイルの名前(の一部となる)。mavenから実行する場合pom.xmlから引き継ぐ。 --> <property name="app.id" value="sample-app" /> <property name="app.name" value="sample-app" /> <property name="app.version" value="2.0" /> <!-- メインクラス --> <property name="app.main-class" value="sample.gui.SampleApplication" /> <!-- ★プレローダクラスのパスの定義★ --> <property name="app.preloader-class" value="proj.green.srcgen.gui.FirstPreloader"/> <!-- JavaFX専用の形式にパッケージングするタスク --> <target name="jfx-package" description="packaging JavaFX archtecture."> <echo>JavaFX用のjarをパッケージングしています。</echo> <!-- タスク定義 --> <taskdef resource="com/sun/javafx/tools/ant/antlib.xml" uri="javafx:com.sun.javafx.tools.ant" classpath="${javafx.tools.ant.jar}"/> <!-- JavaFXのアプリケーション定義:★属性preloaderClassでPreloaderを指定する★ --> <fx:application id="app-info" name="${app.name}" mainClass="${app.main-class}" preloaderClass="${app.preloader-class}"> </fx:application> <!-- JavaFXのパッケージ作成 --> <fx:jar destfile="${jardest}/${app.id}-${app.version}.jar"> <fx:application refid="app-info"/> <!-- アプリケーションの起動パラメータなど:オプション --> <fx:platform javafx="2.2+"> <fx:jvmarg value="-Xms64m" /> <fx:jvmarg value="-Xmx128m" /> </fx:platform> <!-- MANIFEST.MFファイルの内容 :オプション--> <manifest> <attribute name="Implementation-Vendor" value="${app.vendor}"/> <attribute name="Implementation-Title" value="${app.name}"/> <attribute name="Implementation-Version" value="${app.version}"/> </manifest> <!-- パッケージング対象のファイル --> <fileset dir="${dest}"/> <!-- JavaFX-Class-Pathに追加される値:依存するライブラリを定義 --> <fx:resources> <fx:fileset dir="target/dependency" includes="*.jar"/> </fx:resources> </fx:jar> </target> </project>
あとは、普通にパッケージングすればよいです。
> mvn -Dmaven.test.skip=true compile
> ant -f javafx_build.xml jfx-package
作成したjarファイルをダブルクリックまたは、java -jar
JavaFXでスプラッシュの表示
下記を参考にしました。
プレローダを利用する場合、JavaFX用にパッケージングする必要があるため、非常に面倒です。
Java標準の「-splash」オプションを使用すると手軽に実現できます。
スプラッシュを利用したJavaFXのApplicationのサンプル
Splash画像上にJava2Dを利用してメッセージなども表示できます。
AWTの「java.awt.SplashScreen」のメソッドで「#getSplashScreen()」でスプラッシュ画像の情報が取得できます。
- Application#init()メソッドの中で、SplashScreenのオブジェクトを取得します。
- Java2Dなどで起動中のメッセージを書くこともできます。
- Application#start()メソッドの中で、Stageを表示する直前に、SplashScreen#close()でスラッシュ画像を非表示にします。
- close()メソッドを呼ぶと、スプラッシュ画像のオブジェクトが廃棄されます。
package proj.green.srcgen.gui; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.SplashScreen; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.layout.AnchorPane; import javafx.stage.Stage; /** * スプラッシュ画像のサンプル */ public class SampleApplication extends Application { /** * スプラッシュ * <p>起動時に「-splash:<画像ファイル>」を指定する。 */ private SplashScreen splashScreen; /** * Springの初期化 */ @Override public void init() throws Exception { // スプラッシュの更新 splashScreen = SplashScreen.getSplashScreen(); updateSplashMessage("... 初期化中です。"); //TODO: Springのコンテナなどなどの初期化 } /** * スプラッシュのメッセージを更新する。 * <p>Java2Dを使用する。 * @param message */ private void updateSplashMessage(final String message) { if(splashScreen == null) { return; } // 文字を表示するボックスの位置 final int x = 20; final int y = splashScreen.getSize().height - 60; final Graphics2D g = splashScreen.createGraphics(); // 文字を表示する部分を塗りつぶす。 // 前回の表示文字を消すためにも塗りつぶす。 g.setColor(Color.WHITE); g.fillRect(x, y, splashScreen.getSize().width - x - 20, 30); // 文字を設定する g.setColor(Color.BLACK); g.setFont(new Font("SansSerif", Font.PLAIN, 15)); g.drawString(message, x+10, y+20); splashScreen.update(); } @Override public void start(final Stage primaryStage) throws IOException { updateSplashMessage("... 画面の初期化中です。"); //TODO: ステージの組み立て // スプラッシュの非表示 if(splashScreen != null) { splashScreen.close(); } // ステージの表示をフォーカスを充てる primaryStage.show(); primaryStage.requestFocus(); } @Override public void stop() throws Exception { //TODO: Springのコンテナの終了 } public static void main(String[] args) { launch(args); } }
スプラッシュ画像の指定
javaの起動オプションに「-splash:<画像ファイルパス>」を指定します。
画像ファイルは、「JPEG、PNG、GIF」の3種類に対応しています。
ファイルパスは、システムパスで指定する必要があるので、バッチファイルからアプリケーションを起動する際には、
jarファイルのカレントディレクトリに移動して、相対パスで指定するなどしてください。
○ファイル構成├ sample-app.jar ## jarファイル本体 ├ config ├ splash.png ## スプラッシュ画像
@echo off REM 起動用バッチファイルのサンプル %~d0 cd %~p0 set MY_CLASSPATH=.;dependency/*; %JAVA_HOME%\bin\java -cp %MY_CLASSPATH% -splash:config/splash.png sample.SampleApplication
MANIFEST.MFでの指定
【参考】
http://www.javainthebox.net/laboratory/JavaSE6/splash/splash.html
スプラッシュ画像は、起動オプション「-splash」の他に「MANIFEST.MF」に指定することもできます。
○mavenで指定する際には、「maven-jar-plugin」で指定します。
<!-- Splash画像のMANIFESTの指定サンプル --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <mainClass>sample.SampleApplication</mainClass> </manifest> <manifestEntries> <!-- 任意の項目・値が設定可能 --> <Splashscreen-Image>config/splash.png</Splashscreen-Image> </manifestEntries> </archive> </configuration> </plugin>
○JavaFXのパッケージング時に指定する際には専用の
<fx:info title="Sample application"> <fx:splash href="http://my.site/custom.gif"/> </fx:info>