JDK7u6に入ってくるJavaFXのネイティブパッケージ機能を早速試してみました

先日、OracleJava開発に関するblogに "Native packaging for JavaFX" なるエントリが載っていたことを知りました (こちらに江草ロジ子さんによる日本語訳もあります) 。


JavaFX 2.2 adds new packaging option for JavaFX applications, allowing you to package your application as a "native bundle". This gives your users a way to install and run your application without any external dependencies on a system JRE or FX SDK.
なんとJavaFX2.2にはOSネイティブなパッケージを生成する機能が付いてくるということです!
具体的にはJavaFXアプリケーションをWindowsなら.exeや.msiMacなら.appや.dmg、そしてLinuxならrpmの形でアプリケーションパッケージやインストーラーを出力できるようになるということです。
パッケージにはJREJavaFXのランタイムも含めてしまい、配布先にJavaFXのランタイムはおろか、JREが入っていなくてもインストール、実行可能にすることができるということです。
これは今までのJavaの歴史を考えると結構衝撃的な話だと思っています。

と言うわけで早速試してみました。

この機能はJDK7u6の最新版のDeveloper Previewに入っているので、まずは以下の場所からダウンロードします。
http://jdk7.java.net/download.html

自分はMac環境で試しました。ダウンロードしたインストーラーを使ってインストールするだけです。
既にJDK7のGA版をインストールしている場合は上書きしてしまうので注意してください。

$ java -version
java version "1.7.0_06-ea"
Java(TM) SE Runtime Environment (build 1.7.0_06-ea-b14)
Java HotSpot(TM) 64-Bit Server VM (build 23.2-b05, mixed mode)

$ /usr/libexec/java_home 
/Library/Java/JavaVirtualMachines/jdk1.7.0_06.jdk/Contents/Home

自分の環境だと、NetBeansJavaプラットフォーム設定の変更も必要でした。以下のスクリーンショットのように、デフォルトJavaプラットフォームの設定で、JDK7u6のパスを指定する必要があります。

では早速試してみます。NetBeansのビルドでネイティブパッケージを生成したい場合、NetBeansJavaFXアプリケーションプロジェクトの直下にあるbuild.xmlに対して、次のように -post-jfx-deploy タスクをオーバーライドします。fx 名前空間の記述の追加が必要なことに注意してください ( タグの記述を参照) 。

<project name="MouseInfoSample" default="default" basedir="." xmlns:fx="javafx:com.sun.javafx.tools.ant">

(中略)

    <target name="-post-jfx-deploy">
        <fx:deploy width="${javafx.run.width}" height="${javafx.run.height}" nativeBundles="all"
            outdir="${basedir}/${dist.dir}" outfile="${application.title}">
             <fx:info title="${application.title}" vendor="${application.vendor}"/>
             <fx:application name="${application.title}" mainClass="${javafx.main.class}">
             </fx:application>
             <fx:resources>
                 <fx:fileset dir="${basedir}/${dist.dir}" includes="${application.title}.jar"/>
             </fx:resources>
        </fx:deploy>
    </target>
</project>

ポイントは タグの属性に入っている nativeBundles="all" という記述です。これで実行しているOSに応じたネイティブパッケージを生成するようになります。

これでNetBeansの構築を実行したところ、appの生成には成功しましたが、dmgの生成には失敗しちゃいました。

Launching <fx:deploy> task from /Library/Java/JavaVirtualMachines/jdk1.7.0_06.jdk/Contents/Home/lib/ant-javafx.jar
Using base JDK at: /Library/Java/JavaVirtualMachines/jdk1.7.0_06.jdk
Creating app bundle: /Users/aoetakashi/NetBeansProjects/MouseInfoSample/dist/bundles/MouseInfoSample.app
Building DMG package for MouseInfoSample
java.io.IOException: Exec of failed with code 1 command [[osascript, /var/folders/m5/vk8q5qx16yd2scc1jt0mlv100000gn/T/build3045467055592762416.fxbundler/macosx/MouseInfoSample-dmg-setup.scpt] in unspecified directory
	at com.sun.javafx.tools.packager.bundlers.IOUtils.exec(IOUtils.java:130)
	at com.sun.javafx.tools.packager.bundlers.IOUtils.exec(IOUtils.java:108)
	at com.sun.javafx.tools.packager.bundlers.MacDMGBundler.buildDMG(MacDMGBundler.java:262)
	at com.sun.javafx.tools.packager.bundlers.MacDMGBundler.bundle(MacDMGBundler.java:71)
	at com.sun.javafx.tools.packager.PackagerLib.generateNativeBundles(PackagerLib.java:453)
	at com.sun.javafx.tools.packager.PackagerLib.generateDeploymentPackages(PackagerLib.java:434)
...

でも、この例外メッセージが出る前に、何故かそのdmgが以下のスクリーンショットのように「マウント」はされていたんですよね。うーむ不思議だw

いくつかのJavaFXプロジェクトで試しましたが、同じ結果でした。まあ、今回はここについてはまだ深くは調べていません。とりあえずappが出来たので自分的にはOKですw
で、できあがったappはちゃんとダブルクリックで普通に起動します。デフォルトでも結構かっこいいアイコンです。
でも、ファイルサイズを見てみると...

166.9MBだとぉ!?
ちなみにアプリ本体のJARのサイズは20KBです。いったい何が入っているんだと思って中身を見てみると...。

はい、JDK丸ごと入っていました。いくら何でもワイルドすぎやろこれwww

とまあ、こんな感じでした。色々と問題はありますが、まだ実験段階ですし、これから少しずつ洗練されていくでしょう。
アプリケーションの配布形態としてネイティブパッケージという選択肢が出てきたことは素直に嬉しいことだと思っています。
ランタイムごと配布するので、配布先の環境のことを考慮しなくてもいいというのは色んな場面で効いてくるでしょう。例えばなかなかソフトウェア環境を更新してくれない企業向けとか...。*1
もっとも、これはデスクトップアプリ向けというよりはiOSWindows Metroの方をにらんで用意した機能だと見ています。

と言うわけで皆さんも是非試してみてください。
今度はWindowsでも試してみよう。

*1:以前、電子政府で要求JREのバージョンがばらばら、バージョンアップへの追従も遅いという問題が報じられていたことがあったように記憶していますが、そういうのにも向いていそうですね。

JavaFXで画像を使ったボタンを作る方法

ちょっとしたメモです。

RIAを開発するとき、デザイナさんと連携して作ることが多いと思います。
ボタンのようなコントロールについても画像として素材を作ってもらい、それを組み込んで使うというシチュエーションも結構あることでしょう。
というわけでJavaFXで画像を使ってボタンを作る方法です。

JavaFXCSSを使って装飾することができます。HTMLのCSS2.1やCSS3をベースにしており、多くの場合同じプロパティを使うことができます。ただし、ベンダープレフィックス "-fx-" を付ける必要がありますが。

画像をボタンの背景として使いたい場合、CSS3のborder-image属性を使うことができます。次のようにCSSを作成します。

.img-button {
    -fx-border-image-source: url('img/btn.png');
    -fx-border-image-slice: 4 5 4 5 fill;
    -fx-border-image-width: 4 5 4 5;
    -fx-border-image-repeat: stretch;
    -fx-border-color: null;
    -fx-background-color: null;
    -fx-text-fill: white;
}
.img-button:hover {
    -fx-border-image-source: url('img/btn_hover.png');
}
.img-button:pressed {
    -fx-border-image-source: url('img/btn_pressed.png');
}
.img-button:disabled {
    -fx-border-image-source: url('img/btn_disabled.png');
}

border-image-slice プロパティを使うことで、画像を枠の部分と中央部分に分割し、枠部分の拡大率を保持したまま中央部分のみを拡大縮小する、いわゆる「9スライス」も指定可能です。fill も指定して、真ん中も塗りつぶすようにします。

border-image-width プロパティでボーダーの幅を指定します。border-image-repeat で stretch を指定すると、中央は引き伸ばされるようになります。
ベンダープレフィックスを取り除けば、HTMLのCSSと同じになることが分かります。

文字の色については -fx-text-fill プロパティで指定します。これはHTMLとは異なるので注意が必要です。
後は、border-color、background-color を null にして、従来の描画を消せばOKです。
hover や pressed といった疑似クラスもHTMLの場合と同じように指定可能です。

Java側では次のような感じでCSSを設定します。

        final Button imgBtn = new Button("これは画像を使ったボタンです");
        imgBtn.setPrefHeight(40);
        imgBtn.getStyleClass().add("img-button");

実行するとこんな感じで画像を背景にしたボタンが表示されます。わざと縦方向も伸ばしていますがちゃんと四隅を崩さずに伸ばしているのが分かりますね。

スクリーンショットじゃ分かりませんが、マウスオーバーやマウスクリックでも用意した画像に切り替わります。

とまあこんな感じで割とHTMLでのCSSと同じように書けそうです。HTMLデザインの技術を活かすことができるというのは結構なアドバンテージではないかと思っています。*1

*1:FlexでもCSSは使えますが、プロパティはHTMLで使うCSSとはかなり異なります。

JavaFXでxeyes作ってみました

今の自分の仕事場は環境的に結構恵まれています。広い机にエルゴヒューマンの椅子。
そしてディスクプレイが27インチのデュアルです! (iMac+Thunderbolt Display)
広いディスプレイはやっぱり快適です。あまりに快適なので家でも27インチのUltra Cinema Displayを買っちゃったくらいです。

でも広いディスプレイだと1つ困ることがあります。それはマウスカーソルを見失いやすいということです。
そこで古き良きxeyesを使うことにしました。(確かxeyeが元々作られた理由ってマウスカーソルの位置を把握するためでしたよね?)
ところがMacにはxeyesが確かに付属しているのですが、これはX Window上で動くアプリケーションで、Xのアプリケーション上にマウスカーソルがあるときしか反応してくれません...。

というわけでJavaFXを使って自分で作ってみることにしました。
が、まず一番最初でつまずきます。今のJavaFXAPIではマウスのグローバルな座標を取る手段が見当たりません。
仕方が無いのでAWTの MouseInfo を使って取得しようと思ったのですが、JavaFXのアプリケーション上で使うと、HeadlessExceptionが飛びます。
JavaFXはAWTを全く使わず一から作り直しているので、AWT的にはヘッドレスで動いていることになるのです。(システムプロパティ java.awt.headless に true がセットされています)

(2011/12/26 修正)
櫻庭さんからご指摘があり、SwingのEDT上で実行すれば、Swingを土台とせずともHeadlessExceptionは飛ばないとのことでした。
簡単なサンプルで確認したところ、Windows環境では問題なく動作しました。ただ、Mac環境ではやはりHeadlessExceptionが送出され、どうもMac環境固有の問題だったようです。
ただ、WinとMacで微妙に実行環境が異なるところがあったので (前者はJDK7update1 + JavaFX2.0.2で後者はJDK6update29 + JavaFX2.0.1beta) 、後ほど時間があるときにもう少し詳しく再現条件について調べてみます。
あと、改めてJavaFXとして作ってみます。
櫻庭さん、ご指摘ありがとうございました!

(2012/02/21 追記)
どうもJIRAで報告されているRT-13739が近い感じです。一応修正ターゲットは2.1になってますが、これを書いた時点ではまだアサインがないようです。

結局Swingを土台にしてその上にJavaFXで作ることにしました。全ソースコードはgistに貼り付けてあります。
https://gist.github.com/1519410

ちょっとしたアプリケーションですが、結構学ぶことがありました。
まず、Swingアプリケーション上にJavaFXアプリケーションを構築する方法です。

public class SwingFXEyes extends JFrame {
    private JFXPanel jfxPanel;
    private Eye leftEye;
    private Eye rightEye;
    private Timer timer;

    public SwingFXEyes() throws HeadlessException {
        initComponents();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new SwingFXEyes().setVisible(true);
            }
        });
    }

    private void initComponents() {
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        jfxPanel = new JFXPanel();
        add(jfxPanel);

        Platform.runLater(new Runnable() {
            public void run() {
                initJFXComponents();
            }
        });
        pack();
    }

    private void initJFXComponents() {
        Group root = new Group();
        Scene scene = new Scene(root);

        leftEye = new Eye();
        rightEye = new Eye();
        rightEye.setLayoutX(leftEye.prefWidth(-1) + 5);
        root.getChildren().addAll(leftEye, rightEye);

        jfxPanel.setScene(scene);

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                startTimer();
            }
        });
    }

Swing上にJavaFXコンポーネントを載せるには JFXPanel を貼り (initComponents) 、その上にJavaFXのシーングラフを構築 (initJFXComponents) します。目玉部分は独自コンポーネント Eye クラスとして作りました。
注意点としてはSwingとJavaFXは実行スレッドが異なるので、互いのコンポーネントを触るときは SwingUtilities.invokeLaterPlatform.runLater を経由して触る必要があります。これがちょっとめんどくさいです。

マウス位置の取得はSwingのタイマーを使って行いました。

    /**
     * マウス位置取得処理を行うタイマーを起動する。
     */
    private void startTimer() {
        timer = new Timer(50, new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                updateMousePosition();
            }
        });
        timer.start();
    }

    /**
     * グローバルのマウス位置を取得し、目のマウス位置を更新する。
     */
    private void updateMousePosition() {
        final Point mouseLocation = MouseInfo.getPointerInfo().getLocation();
        Platform.runLater(new Runnable() {
            public void run() {
                updateEye(mouseLocation.x, mouseLocation.y);
            }
        });
    }

    /**
     * 左右のEyeにコンポーネントからの相対的なマウス位置を渡す。
     */
    private void updateEye(double mouseX, double mouseY) {
        Point panelLocaiton = jfxPanel.getLocationOnScreen();
        leftEye.updateMousePosition(mouseX - panelLocaiton.x, mouseY - panelLocaiton.y);
        rightEye.updateMousePosition(mouseX - panelLocaiton.x - leftEye.prefWidth(-1) - 5, mouseY - panelLocaiton.y);
    }

AWTの MouseInfo を使って、マウス位置を取得し、目玉コンポーネントにはコンポーネントからの相対的な座標を渡すようにしています。
JFXPanel は javax.swing.JComponent を継承しているので、getLocationOnScreen メソッドを使って画面上での位置を取得可能であることを利用しました。

目玉は独立したコンポーネントとして作ってみました。JavaFXでは子を持つコンポーネントParent クラスを継承する必要があります。

public class Eye extends Parent {
    private static final double CENTER_X = 42.5;
    private static final double CENTER_Y = 62.5;
    private static final double ELLIPSE_RADIUS_X = 40d;
    private static final double ELLIPSE_RADIUS_Y = 60d;

    private Circle eye;

    public Eye() {
        super();
        createChildren();
    }

    private void createChildren() {
        final Ellipse ellipse = new Ellipse(CENTER_X, CENTER_Y, ELLIPSE_RADIUS_X, ELLIPSE_RADIUS_Y);
        ellipse.setStrokeWidth(5.0);
        ellipse.setStroke(Color.BLACK);
        ellipse.setFill(null);

        eye = new Circle(CENTER_X, CENTER_Y, 10d, Color.BLACK);

        this.getChildren().addAll(ellipse, eye);
    }

    /**
     * 自分の位置からの相対的なマウス位置を受け取り、自身のステータス (つまり目玉の位置) を更新する。
     * @param mouseX マウスのx座標
     * @param mouseY マウスのy座標
     */
    public void updateMousePosition(double mouseX, double mouseY) {
        // マウスの自コンポーネントの中心からの相対座標を算出
        double localMouseX = mouseX - CENTER_X;
        double localMouseY = mouseY - CENTER_Y;
        computeEyePosition(localMouseX, localMouseY);
    }

    private void computeEyePosition(double mouseX, double mouseY) {
        double parameter = Math.atan2(mouseY, mouseX);
        double eyeX = (ELLIPSE_RADIUS_X - 7.5) * Math.cos(parameter);
        if (Math.abs(mouseX) < Math.abs(eyeX)) {
            eyeX = mouseX;
        }
        double eyeY = (ELLIPSE_RADIUS_Y - 7.5) * Math.sin(parameter);
        if (Math.abs(mouseY) < Math.abs(eyeY)) {
            eyeY = mouseY;
        }
        eye.setCenterX(eyeX + CENTER_X);
        eye.setCenterY(eyeY + CENTER_Y);
    }
}

目玉の縁を Ellipse で、目玉を Circle で書いて自分の子供に追加しています。
外からマウスの相対的な位置をもらって目玉の位置を決めるようにしました。 Math.atan2 を使って極座標に変換しています。

ということでこんな感じでできました!

JavaFXユーザグループ第6回勉強会に行って来ました

前回に引き続き第6回JavaFX勉強会に参加してきましたので、その時のメモを貼っておきます。色々あって公開が遅くなっちゃいました。
今回は参加者が随分増えていて驚きました。やはりJavaOneOracleJavaFXを全面に押し出したことや、GroovyやScalaの話題があったからでしょうか。

何が変わった JavaFX 2.0 by 櫻庭さん (@skrb)

JavaOneでの話題や、正式版となったJavaFX2.0についての説明が中心でした。

JavaOneでのお話し
  • 今回のJavaOneではJavaSE、EE、MEそれぞれで大きな動きがあった。
  • Java8ではJavaFX3.0がSwing/AWTに代わる立場に。
    • その前に多分JavaFX2.1が来る。
    • 現時点ではまだJavaSEに入る水準に達していない。
  • JavaMEの変化がサブライズ。
    • CDCとSE Embeddedが一緒になった。
      • JavaMEは10年前の規格で、その時に比べると携帯端末の性能は大幅に上がっているし。
    • NandiniさんがiPadでデモ! (JavaFXが動いた!)
      • もちろん実際に載せられるようになるかは政治的な話もあるので...
JavaFX2.0で変わったこと

前回のご説明とかぶっている内容も結構あったので、差分点を中心にメモっています。

  • シーングラフをJavaで書くのは辛いので、XMLでも書けるようにした。それがFXML。
  • Production Suiteなくなっちゃった!
    • Adobe製品からの取り込みができなくなった。
    • SVG経由で取り込むようなライブラリを自作した。(後日公開するとのことです)
  • JSONのParserがなくなっちゃった。JavaEE7にも入るので、まとめようとしているのかな?
デモ

テキストエリアに入れたコードをその場で解釈して実装するアプリを使ってデモしていました。

  • WebView
    • HTML文字列の解釈もOK。
    • この上でHTML5で作っても大抵のアプリは提供できちゃいますね。(身も蓋もないこと言いますねw)
    • 純粋な意味でのHTML5CSSJavaScriptは大体OK。WebSocketなど幾つか使えない仕様もある。
  • アニメーション
    • 移動とか回転だったら始点と終点を指定するだけで後は自動補完する。
    • 移動、回転、拡大縮小、パスアニメーションとかができる。
  • Effect
    • 基本 Node に対して setEffect する。
    • 徐々に効果を掛ける時はタイムラインを作って少しずつ変えていく。
  • CSS
    • Scene に対して add する。つまり複数指定がOK。
    • 接頭辞 "-fx" が付く。
  • Bind
    • オブジェクト間のプロパティの結びつけ。
    • MVCGUIを構築する場合、MからVに対してはオブザーバー同期を行うが、これは実装がめんどくさい。それを解決するのがBind。
    • 高レベルAPI、低レベルAPIがあり、パフォーマンスを出したかったら低レベルAPIを使う。
まとめとか
  • OpenJDKに入ることに。OpenJFXという昔聞いたような名前でw
  • ツールとしてはNetBeansに加えて、Scene Builderが発表された。
    • ただしこれはFlashで言えばFlash Builderのようなもので、デザイナ向きではない。
  • 次のバージョンは多分2.1。もしかしたら3かも。その前にJavaSE7対応ということで2.01が出そう。
質疑応答

Q. まだJavaSEに組み込める水準ではないとは?
A. まだ意図した動きがしない所があるとか、Prismが対応しているGPUがまだ少ない所とか。
Q. CSSの属性名に何で接頭辞が入っている?
A. 何ででしょう、困りますよねえ (爆
Q. FXMLには日本語が使えるか?
A. XMLなのでたぶん大丈夫なはず。
(これは私がコメント) 自分が試してみたところ、属性では普通に使えましたよー。
※こんな感じで試してました。

<VBox id="boxPane" prefHeight="200" prefWidth="320" spacing="10"
    xmlns:fx="http://javafx.com/fxml" fx:controller="samplefxmlapplication.Sample">
    <children>
        <Button id="button" prefWidth="80" text="Click Me!" onAction="#handleButtonAction" fx:id="button" />
        <Label
            id="label" prefHeight="16" prefWidth="200"
            text="クリックしたら表示が変わるよ" fx:id="label">
            <alignment>
                <Pos fx:value="CENTER"/>
            </alignment>
        </Label>
    </children>
    <alignment>
        <Pos fx:value="CENTER"/>
    </alignment>
</VBox>

Q. コンパイルはどのように行うのか?FXMLは?
A. 普通にJavaアプリケーションとしてビルドする。FXMLはJavaプログラム中でロード処理を書く。(デコンパイルしたら中でStAXを使ってた)
Q. bindを入力チェックとかに応用できるか?
A. 低レベルAPIを使えば割と好きに書けるのでいけます。
Q. CSSのリファレンスが見当たらなかったのですが。(<- 質問者私です)
A. OracleのJavaFXのページからリンクがありますよ。

すみません、めっちゃ正面玄関にありましたね!失礼しましたー。
Q. Swingとの混在はやりやすい?
A. スレッドが別になるのでやりにくい。また、Swing上でJavaFXを動かすとJava2D上で動くことになるので遅くなる。

感想

JavaOneではJavaFXが全面に押し出されていて、自分も結構驚きました。ただ、現時点ではJavaSE本体に入るレベルじゃないというのは分かります。AWT/Swingと決別して一から作り直しているので、AWT/Swingが長い時間を掛けて蓄積してきた資産がそのままでは使えないですからねえ。自分でいじっている時でもグローバルなマウス位置が取れなくて面食らったりとか*1、まだまだ不足しているところはあるという印象です。
FXMLは結構面白いと思っています。XML側とJavaコード側を結びつける仕組みがMXML等の類似技術よりも良く考えられているという印象です。
MXMLコンパイルするとActionScriptクラスに変換されますが、FXMLはあくまでXMLドキュメントのまま読み込む形になっているのもちょっと変わっていますね。この方法が本当にいいのかは分からないですが...。

GroovyFX – Groovy な JavaFX 2.0 by 関谷さん (@kazuchika)

「プログラミングGROOVY」の共著者でもある関谷さんから、GroovyFXについて、デモアプリケーションと共に紹介して頂きました。デモアプリケーションが素晴らしかったです。

Groovyとは?
  • 書いたことある人?
    • (会場の半分くらいでした。すみません、実は自分もこれまでGroovyと接する機会がありませんでした...)
  • JVM上で動くスクリプト言語の中でも、特にJava共生するという姿勢がある言語。
    • 文法的に近いし、ツールや文化も近い。
GroovyFX
  • JavaFXをより簡単に書けるようにラップしている。
  • まだアルファ段階で、SVNから落として自分でビルドする必要がある。
  • Groovyのビルダーを活用したDSLを提供する。宣言的にシーングラフやタイムラインを構築できる。
  • ビルダーとは?
    • Groovyの柔軟な言語仕様をフル活用して、オブジェクトを構築する仕組み。
    • HTMLとかSwingやAnt、CLIに対応したビルダーがある。
  • 様々なシンタックスシュガーを提供。
    • Duarationを100.msとか5.sと書ける。(Numberにモンキーパッチでメソッドを増やしている)
    • 擬似定数の提供。
    • 属性値の自動型変換でFontやPoint3Dの値をリテラルで書くことができる。
デモアプリケーション
  • Google+のプロフィールを取ってくるアプリ。
    • クロージャの中で構造だけでなく、effectの設定とかも書き下せる。
    • ParallelTransitionがすごく見通しよく書ける。
  • WebViewのデモ。
    • HTML5Canvasを使ってグラフィック生成。JavaScriptコードも連動している!
    • Twitter4Jを使って、ハッシュタグ付きのつぶやきを拾って、Canvasにサウンドと共に表示するデモが見事!
    • 非同期処理も綺麗に書ける印象。
その他
  • バインディングは現在見直しが入っているとのこと。
  • Griffonフレームワークと連携する計画が。MVCベースのフレームワークになる模様。
  • プレゼンテーションツールPreziのGroovyFX版である、Greziというものも開発されているとのこと。
  • 12/1 に JavaDeveloper Workshop を開催します!
    • Nandiniさんが来るとのこと!
感想

Groovy、意外とこれまで触る機会がなかったのですが、いいですねえ。Javaを補佐する便利な小道具という感じで。
GroovyFXでUI構造を記述すると、見通しはFXMLよりもずっといいですね。あとは見直し中というバインディングの部分がどうなるのか、注目しています。

JavaFX 2.0 + Scala → ScalaFX by 深井さん (@fukai_yas)

こちらはScalaFXの紹介です。深井さんはScalaは業務ではなく趣味で触っているとのことでした。
ScalaFXはまだまだ始まったばかりの状態のようですが、こちらはこちらでとても興味深いものがありました。

ScalaFXの概要
  • JavaFXの各クラスにラッパーを提供する。
  • Scalaの柔軟な文法をフルに活用している。
  • まだ現時点では未実装なものが多く、これからといったところ。
  • そのままではAppletやWebStartアプリケーションを作ることができない。
シーングラフの構築
  • ぱっと見はGroovyFXと同様、JavaFXScriptに似せた書き方になっている。
    • プロパティを組み立てている所が少し違う。"foo_=" というsetterメソッドが "foo = " と呼び出せるというScalaシンタックスシュガーを利用している。
  • JFXAppがmainメソッド起動前提なのでAppletがNG。
    • Appletで使いたかったらJavaFXのApplicationを直接使う。
  • バインドは次のように書く。複雑な処理も書ける。
        new Rectangle {
          width <== stage.widthProperty / 2
          height <== stage.heightProperty / 2
          fill <== when (checkbox.selected) then Color.RED otherwise Color.BLUE
        }

何これ、めっちゃクールなんですけど!
※同じ事をJavaで書くと次のようになります。分かりやすさが全然違いますよね!

        Rectangle rect = new Rectangle();
        rect.widthProperty().bind(stage.widthProperty().divide(2));
        rect.heightProperty().bind(stage.heightProperty().divide(2));
        rect.fillProperty().bind(new ObjectBinding<Color>() {
            {
                super.bind(checkbox.selectedProperty());
            }
            @Override
            protected Color computeValue() {
                return checkbox.selectedProperty().getValue() ? Color.RED : Color.BLUE;
            }
        });
  • GroovyFXと同様、Duarationとかを書きやすくするようにしている。
まとめ
  • Scalaの特徴をフルに活かしたDSL
    • Scalaの勉強にもなるので是非!
  • まだまだ始まったばかりのプロダクト。
感想

こちらはこちらでScalaの機能をフルに活かして、見通しのいいDSLを提供しているな、と思いました。バインドの記述が実にいいです!
個人的にはScalaは勉強を始めた所という段階なのですが、そうか、これをネタに勉強すればいいのか。

その他

  • 次回は来年1月くらいに。ツールをメインテーマに!

全体を通しての感想

冒頭にも書きましたが参加者が増えて驚きました。懇親会でも様々なバックグラウンドを持つ人が集まってきているという印象でした。JavaEE系の人とかAndroidの人とか自分みたいにHadoop触っている人とかw
少しずつ盛り上がり始めているのは確かだと思っています。別のエントリでも書きましたが、Flexがあんなことになったので、実は今JavaFXは結構いい立ち位置にあるのかも知れません。

*1:これについては別途エントリを書こうと思っています。

MacでJavaFX2.0を触り始めてみる

先日のJavaOneでJavaFX2.0が正式発表され、そして待望のMac向けDeveloper Previewも登場しました。
過去にRIA開発をやったことがあるのでJavaFXにはすごく興味があります。今後果たしてJavaFXが来るのかどうか?という疑問はありますが、自分としては特に業務系システムにおけるクライアントとして今後徐々に採用されていくのではと考えています。
というのも、業務系システムではクライアントアプリケーションをSwingで開発することが意外と多い気がするからです。サーバーサイドをJavaで開発していると、やっぱりクライアントもJavaで開発した方がやりやすいですし。*1
で、OracleはSwingをJavaFXにシフトさせるつもりのようですし、Oracleの用意したJavaFXのデータシートを見ても、JavaFXを "Rich Enterprise Client Applications" とうたっており、JavaFXエンタープライズ向けのクライアント開発基盤として押していく姿勢を見せています。なので、段々業務系のシステム開発ではJavaFXを使う場面が出てくるんじゃないかなー考えています。(数年くらいかかるかも知れませんが)

という訳で今のうちからJavaFX触るぞーと考えて早速Macに入れてみたのですが、意外と躓いたところが結構あったので環境を作って触り始めてみるところまでをメモっておきました。

JavaFX本体とサンプルのダウンロード

ダウンロードサイトは以下です。ダウンロードにはOTNのアカウントが必要です。
http://www.oracle.com/technetwork/java/javafx/downloads/javafx2-macosx-487281.html
SDKの方はZIPアーカイブになっているので、適当な場所に解凍すればいいです。
サンプルの方は次のように、SDKのインストールディレクトリの下に置く必要があります。そうでないと動きません。リリースノートではこの辺が割とさらっと書かれているので注意してください。

javafx-sdk2.0.2-beta/
├── bin/
├── docs/
├── javafx-samples-2.0/  <- ここ
├── rt/
└── tools/

NetBeans7.1 betaのセッティング

次はNetBeansです。NetBeans7.1 (現在ベータ版) はJavaFX2.0をサポートしているので是非入れましょう。後述しますが、NetBeansを入れておくとサンプルを使っての勉強もやりやすくなります。
Windowsの場合だと、先にJavaFXをインストールしておけば、その後にNetBeansを入れるとNetBeans側で自動認識し、すぐに使えるようになりますが、Mac版は手動でセットアップが必要となります。(Windows版のJavaFXインストーラが用意されており、基本的には決まったディレクトリに入りますが、Mac版は適当なディレクトリに解凍するだけなのでこの辺りは致し方ないですね)
これがちょっと面倒です。NetBeans側でも解説を用意していますが、Windows向けの内容となっており、Macユーザーには分かりにくくなっています。

まずは以下のサイトからNetBeans7.1 betaをダウンロード、インストールします。betaなのに日本語版もちゃんと用意されています。この辺りNetBeansはスバラシイ。
http://dlc.sun.com.edgesuite.net/netbeans/7.1/beta/

NetBeansJavaFXの開発を行うためには、"JavaFX enabled" なJavaプラットフォームを用意する必要があります。
まず、メニューから [ツール]-[Java プラットフォーム] を選択して、Javaプラットフォームマネージャーを起動します。

起動したプラットフォームマネージャーで [プラットフォームを追加...] ボタンをクリックし、新しいJavaプラットフォームを追加します。
Java自身のプラットフォームフォルダの選択はデフォルトと一緒でいいです。

プラットフォーム名は何でもいいのですが、"Default_JFX_Platform" という名前にしておいた方がいいみたいです。(下のスクリーンショットでは違う名前にしているので注意!)
これはWindows版のNetBeansJavaFX環境を自動認識した際に作られるJavaプラットフォームの名前のようで (すみません、Win版は未チェックです) 、後述するサンプルアプリケーションから作成したNetBeansプロジェクトは、Javaプラットフォームがこの名前になっていることを前提としているからです。

作成したプラットフォームの設定パネルには [JavaFx] という名前のタブが追加されているはずです。これをクリックして、SDKやランタイムのディレクトリを指定します。
[JavaFX SDK] にはSDKのインストールディレクトリを、[JavaFX Runtime] にはSDKのインストールディレクトリの下にある rt というディレクトリを指定します。設定途中で NPE が発生したという警告ダイアログが出ますが、ランタイムの設定を行ったら直ります。

これでNetBeans上でJavaFXプロジェクトを作成することができるようになります。

JavaFXプロジェクトを作成する際、[JavaFX Application]、[JavaFX Preloader]、[JavaFX FXML Application] の3種類から選べます。
普通は [JavaFX Application] を選びます。UIの構造定義にFXMLを使いたい場合は [JavaFX FXML Application] を選びますが、FXMLを使ったアプリケーションの雛形を作ってくれる以外、特に違いはありません。[JavaFX Preloader] はアプリケーション起動時のリソースロード中に表示するプリローダーを作成するためのプロジェクトです。

FXMLとはJavaFXのUI構造を宣言的に記述することができるマークアップ言語で、FlexMXMLWPFXAMLと同じような立ち位置の技術です。解説はこことかここにあります。
早速NetBeansでこれをサポートしてくれたと喜んだのですが、残念ながらマークアップの補完とかは全然行なってくれませんでした。(;_;)

サンプルのJavaFX Ensembleがスバラシイ

サンプルには4種類のサンプルアプリケーションが収録されていますが (ブロック崩しとかもあります)、中でもJavaFX Ensembleが素晴らしいです。
Ensemble.jar を実行すると起動します。

いわゆるサンプルアプリケーション集で、SwingのSwingSetに相当するものです。サンプルアプリケーションとJavaDocが収録されており、サンプルとドキュメントを相互に行き来できるようになっていて、勉強するには最適なアプリケーションになっています。
GUIフレームワークの勉強には豊富なサンプルの存在がとても重要だと思っています。昨年の今頃、SmartClientというJavaScript製RIAフレームワークを使った開発を行なっていたのですが、こちらもSDKに付属していたサンプルが豊富で、比較的短い期間で習得できたことを憶えています。JavaFXは後発なだけに、こういった学習環境に力を入れていることはとてもいいことだと思いました。

さらにこのサンプル、ソースコードも閲覧できますが、[Save NetBeans Project...] というボタンがあり、ここからNetBeansプロジェクトを作ってくれます! サンプルを見て、自分の手でいじってみたいと思ったらすぐに試せるようになっているわけです。これはありがたいです。

まだかなりバグバグ...

さて、Mac版はまだプレビュー版なだけに、ちょっと触ってみただけでも結構バグが出てきました。まあ致し方ないですが。リリースノートでも色々載っていますが、それ以外にも次のようなのが目に付きました。

  • TextFieldやTextAreaで日本語が入力できない
  • TableViewでカラムのドラッグ&ドロップが効かない (さらに適当にいじっているとハングアップ...)
  • RichTextEditorが重い&いじっているとハングアップ...
  • WebViewはまだまだレンダリングが乱れまくり


そんな訳で、自分もこれからこのサンプルを中心にちょくちょく勉強していこうと思っています。現状業務が忙しいのでほんとにちょくちょくって感じになりますが...。

*1:ここでクライアントを無理にJavaScriptで頑張ろうとすると大変なことになるケースをしばしば見掛けたり...

JavaFXユーザグループ第5回勉強会に行ってきました

JavaFXユーザグループ第5回勉強会に参加してきました。そのメモと感想をまとめました。途中仕事場からトラブルの電話が掛かってきたので、一部聞けなかったところがありましたが...。
JavaFXの勉強会に参加するのはこれが初めてです。先日のエントリにも書きましたが、ここ最近JavaFXにはすごく注目しているので楽しみにしていました。

What's new JavaFX 2.0 by 櫻庭 (@skrb) さん

JavaFXのこれまでの経緯
  • JavaFX発表当初の目論見は...
    • デスクトップ、携帯、セットトップボックスなど全部カバーするつもりだった!
    • JavaFX Mobileとか他の会社を買収までしたのにすぐつぶれた
      • 結局残ったのはデスクトップだけ
  • JavaFX2.0ではJavaFXScriptをやめ、Javaベースに
  • Swingとの関係は?
    • Swingは今後AWTと同じくレガシーな存在に
    • Java7ではSun/Oracle自身が作ったSwingの新機能はない。 (オープンソース由来のJXLayerくらい)
    • これから新たにJavaGUIを作るとしたらJavaFXがオススメ!
JavaFXScriptをやめた理由
  • 元々JavaFXScriptはSwingを利用したアプリケーションを作りやすくするための言語だった
    • でもそれがAPIを作るための言語に変わり、コンパイル言語に変わった
      • コンパイラを作るための開発リソースが足りなくなった
        • javacのチームとリソースの取り合いになった
  • 著名なSwing開発メンバーも結構抜けてしまった
  • 開発するためのリソースを割けなくなった...というのがOracle側の言い分
  • 実際は...
  • 残念だけど最善の策ではある?
良くなった点
  • コンパイラ作らなくていいので開発スピード上がるはず
    • 実際ロードマップ通りのペースでリリースされている
  • パフォーマンスがよくなる
悪くなった点
  • 記述量多いし複雑
  • JavaFXScriptでサポートされた様々な機能がなくなった
    • 宣言、バインド、トリガー、関数型、型推論、国際化...
    • バインドはAPIベースなので扱いにくい
JavaFXのUIコントロール
  • WebView
    • ちゃんとしたブラウザが使えるようになったのは大きい!
    • 結構綺麗に表示される
    • JavaFXからWebKitをコントロールする部分がまだまだ、DOMの操作も結構バグがある
  • エフェクト、アニメーション
    • 最初から組み込まれていて簡単に扱える
      • SwingだとJava2Dでごりごりと...
  • バインド
    • Flex、Sliverlightでおなじみ
    • ちょっと書きにくい
    • 現在アンバインドはできない
  • メディア
    • 元々Javaがすごく弱かったところで、これまでとは雲泥の差
    • 様々なメディアタイプをサポートしている
  • Prism
  • その他CSSが使えたり、JSONのパーサがあったり
感想

JavaFX2.0での路線変換 (JavaFX Scriptをやめる、デスクトップアプリに集中) は良くも悪くもきちんと現実を見据えて選択と集中を行った結果なんでしょうね。Oracleらしいと思います。でもJavaで手続き的にUIツリーを組み立てるのは面倒なので、UI構造の定義部分だけは宣言的な記述を残して欲しかったですが。
業務系のシステム開発ではSwingでGUIを作ることが結構あります。そこに新しくモダンな (Javaの) GUIツールキットを提供してくれるのは嬉しいです。懇親会でもちょっと話題にあがったのですが、iOS等のお陰で企業向けシステム開発においてもUIのベースラインが上がっちゃいましたからねえ。
Swingは中々良く出来たGUIツールキットだと思いますが、アニメーションやエフェクト周りが辛かったので、その辺りがJavaFXではお手軽に扱えるようになったのがいいです。

ハンズオン by 櫻庭 (@skrb) さん

ハンズオンではミニブラウザを作りました。短い時間の間でJavaScriptも動くブラウザが簡単にでき、さらに鏡面効果やページ遷移時のスライドアニメーション、ドロップシャドウといった演出も簡単に追加できちゃいました。
以下、ハンズオン時に出てきた説明のポイントをまとめておきます。

  • サイズを指定する時、Swingは外枠の大きさを指定することが多いが、JavaFXは中のコントロールの大きさを指定することが多い
  • AWTと同じ名前のコントロールが多いので注意!
  • WebEngineはページ読み込みの非同期処理をハンドリングできるようにTaskオブジェクトを返すが、TaskクラスはDeprecatedになっている...

ハンズオン後の質疑応答では次のような話が出てきました。

  • SwingとJavaFXの混在は?
    • SwingにJFXPanelを貼ると、その下にシーングラフを構築することができる
  • レイアウトの種類は?
    • SwingのGroupLayout、SpringLayout以外はみんなカバーしている
  • アプリケーションの配布方法は?

NetBeansJavaFXサポートについて by 片貝さん

NetBeans国際化担当のOracle片貝さんから、今後のNetBeansにおけるJavaFXのサポートについてのお話をしてもらいました。ただ、現時点ではまだ余り情報がないようです。

  • NetBeans7ではJavaFXComposerがなくなった
  • 先日JavaFX2.0プラグイン登場
  • NetBeans7.1
    • JavaFX2.0サポートがメインテーマ!
      • NetBeansではリリースするバージョンにおけるメインテーマを「リリースドライバー」と呼んでいるそうです
    • 編集、デバッグ、構築、デプロイをサポート
    • UIデザインツールNetBeansとは別のツールとして提供
      • 具体的にどんなものを出すのかは現時点では不明...
感想

一番知りたかったデザインツールですが、やはり現時点ではほとんど情報がないようですね...。NetBeansとは別になるそうですが。
個人的にはPhotoshopとかにプラグインして、そこでデザイナーがデザインしたものからCSS定義と画像パーツを吐き出してくれるようになれば、まずは十分なのかなあと思っています。ちなみに懇親会でもこの話をしましたが、「それだけだとプログラマとデザイナーの間でラウンドトリップできないので不十分では」という意見を櫻庭さんらから頂きました。このやり方は自分が以前関わったFlexでの開発で行ったやり方だったのですが、確かに実装が始まってからのデザイン変更は少し大変でしたね。


とまあこんな感じで、色んな情報が得られてとっても良かったです。何より懇親会 (結局終電になりましたw) でJavaGUI作りたい、な人達と交流できたのが大きかったです。次回以降も都合が合えばぜひぜひ参加したいです。