JavaFXでJava RIA開発はどれくらい変わるの?

2007年の JavaOneで発表されてから、がぜん注目を浴びている JavaFX ScriptSwingライブラリを使ったプログラミングが簡単にできるようになるということで、これを使えば Javaデスクトップアプリケーションもすぐに開発できるようになりそうです。

 Sunは携帯端末向けのGUIアプリケーションもターゲットとしているようで、JavaFX Mobileというシステムも提供していくとアナウンスしています。こちらは、従来よりもパワーがある携帯端末で、Java SEが動作するようなものを想定しているようです。

 PCのデスクトップだけでなく、この先進的な携帯端末でも動くGUIアプリケーションを簡単に作成できるということが、JavaFX Scriptの売りとなっているようです。昨年から続いているEoDの流れにも沿っているのでしょう。ということで、早速JavaFX Scriptを使ってみました。


図1 JavaFX Script Studiomoto Demoの画面

JavaFX Scriptの使いどころとは?

 JavaFX Scriptは、SunのJavaFXのサイトで紹介されています。RIA(Rich Internet Application)を簡単に実装できることが売りですが、Javaプログラマにとっては、既存のスクリプト言語との関係が気になるところです。Swingライブラリを使ったプログラミングの方が、Javaの文法で行える分、気が楽だというのが正直なところなので、こういったスクリプト言語の存在に価値を見いだすとしたらどこか、というのが最初に気になります。

Webブラウザの出現でUIデザインの仕方は変わった

 一昔前のコンピュータ用アプリケーションの開発においては、ユーザーインターフェイスデザインというのは、開発者が片手間にやっていたり、コンピュータのユーザーインターフェイスに詳しいエンドユーザーが指示をしていたり、というのが普通の世界でした。

 しかし、Webブラウザの出現によって、状況は変わってきています。いまや、Webサービスの開発においては、デザインチームが画面デザインをし、Web開発チームがそれをXHTMLCSSAjaxで実装し、サーバサイドは開発チームがプログラミングをするといった体制で開発が増えてきています。賛否両論はあるようですが、GUIアプリケーションのモデルとして有名なMVCモデルをWebアプリケーション開発に適用していることが多いはずですし、多くのフレームワークは、基本的にこのモデルを採用しています。

RIA開発ではより柔軟なGUIコンポーネントが必要

  このように、RIAの開発が要求されるようになってきていますが、これまでのようにWebブラウザに依存した技術だけでそれを実現するのは難しくなってき ています。これからは、より柔軟に、より高度なGUIコンポーネントを組み合わせることができて、しかもインターネットに対応したアプリケーションを開発 できる技術が必要なのです。

JavaFX Scriptはデザイン側やクライアント開発側で使われる?

  こうして見ると、JavaFX Scriptを使うのは、実はサーバサイドで開発をしているJavaプログラマよりは、現在、XHTML+CSSやAjax回りを使っているWeb開発 チームが一番関係してきそうです。このチームのメンバが、Webアプリケーション開発時にJavaScriptFlashを使っていたのと同じように、デスクトップでも携帯端末でも同じように動作するRIAを開発するに当たって、JavaFX Scriptを使うことになると考えられます。

  ですから、JavaFX Scriptを評価するに当たっては、こういった開発体制で利用できそうなのか、JavaScriptやFlashを使うのと同じくらい簡単に使えるの か、といった項目が重要ではないでしょうか。こんなことを考えながら、いくつかの簡単なサンプルコードを作ってみました。

ダウンロードして、デモを試す

 JavaFX Scriptのオープンソース実装であるOpenJFXのサイトで は、活発に開発がされていて、バージョンアップが頻繁に行われています。アーカイブはzip形式とtar.gz形式が用意されていますので、好きな方をダ ウンロードしてください。ここでは、記事執筆時にダウンロードしたOpenJFX-200705302107.zipを使って動作確認をしていますので、 あらかじめご了承ください。

 OpenJFXのサイトでは、ライセンスは将来的にはGPLとなると書いてありますが、記事執筆時にダウンロードしたものには、「Technology Evaluation License」が同梱されていました。

Java Web Startを使ったデモ

 ところで、このサイトには「Demos」と記載してあるところに、JNLPを使ったJava Web Startで起動するデモも用意されています。ちょっと様子を見てみたいというだけでしたら、このデモをダウンロードして動作させてみるといいでしょう。こういうのを使うと、Java Web Startの良さを実感できるはずです。


図2 JavaFX Script Tesla Demoの画面

デスクトップ上でも、デモを動かす

  ともあれ、手元でも動作をさせてみましょう。ファイルをダウンロードしたら展開します。ここでは、Windows XPを使って確認をしました。展開した結果できたディレクトリは、C:\OpenJFXという名前に置き換えています。なお、後で作成するサンプルコード 用にC:\OpenJFX\sampleも作成しておきました。

 ダウンロードしたファイルに同梱されたjavafxpad.batは簡単なJavaFX Scriptプログラムの開発に使える便利なツールです。前述のJava Web Startのデモにもあります。早速使ってみました。


図3 JavaFxPadの実行例

簡単なJavaFXアプリを作ってみよう!

 さて、ここからはWindows Vistaを使って、実際に簡単なサンプルを作ってみます。ダウンロードしたファイルのbinディレクトリには、javafx.batなどの起動スクリプトがあります。文字コードWindows-31Jのファイルしか使えなくなってしまうので、筆者は次のようなバッチファイルjfx.batを用意して、こちらを使うようにしました。見てのとおり、libディレクトリにあるjavafxrt.jar、Filters.jar、swing-layout.jarを使います。

 また、スクリプトの起動には、net.java.javafx.FXShellクラスを使います。ここでは、ファイルのエンコードをUTF-8としています。プログラムを作成するときには、UTF-8で保存するように気を付けてください。なお、javaコマンドへのパスはあらかじめ通しておきます。

jfx.bat
@echo off
set CP=.;../lib/javafxrt.jar
set CP=%CP%;../lib/Filters.jar
set CP=%CP%;../lib/swing-layout.jar
java -Dfile.encoding="UTF-8" -cp %CP% net.java.javafx.FXShell %1 %2 %3 %4 %5 %6 %7 %8 %9

SimpleSwingSample.java
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class SimpleSwingSample {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI() {
        JFrame f = new JFrame();
        f.setTitle("タイトル:SimpleSwingSample");
        f.setSize(300, 80);
        JButton button = new JButton("OK");
        f.getContentPane().add(button);
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                System.out.println("OK");
            }
        });

        f.setLocation(200, 100);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
    }
}

 コンパイルをして実行してみます。javacコマンドへのパスは通しておいてください。ソースファイルの文字コードを指定する必要があるので、「-encoding」オプションを付けている点にも注意してください。

コンパイルしてjavaコマンドを実行
>javac -encoding UTF-8 SimpleSwingSample.java
>java SimpleSwingSample


図4 SimpleSwingSample.javaの実行画面

JavaFX Scriptで記述すると?

 これを、JavaFX Scriptで記述すると、次のようになります。文法事項については、JavaFX Scriptの言語仕様がまだドラフトであることと、実装も頻繁に更新されていることから、あまりくどくどと説明せずに、重要な点だけを解説することにします。

 一目見て分かることは、非常に簡単に記述できるということでしょう。画面を表すのがFrameで、その属性をCSSと同じような感じに指定できるようになっています。Swing版のプログラムと比較してもJavaFX Scriptの方が断然書きやすそうです。また、SwingUtilitiesも、この程度のプログラムなら必要ないようです。

JavaFX Scriptで記述
import javafx.ui.*;
import java.lang.System;

Frame {
    title: "タイトル:SimpleFxSample"
    screenx: 200
    screeny: 100
    width: 300
    height: 80
    content: Button {
        text: "OK"
        action: operation() {
            System.out.println("OK");
        }
    }
    visible:true
}

 Swingプログラミングでは、Buttonには、addActionListenerメソッドを使って、ActionListenerを登録していましたが、JavaFX Scriptでは、actionという属性にoperation()を指定し、そこでボタンを押されたときの処理を記述します。

 ここでは、java.lang.Systemクラスを使って、「OK」という文字列をコンソール画面へ出力していますが、このクラスをimportしていることに注意してください。また、FrameやButtonといったクラスはjavafx.uiパッケージのクラスで、「import javafx.ui.*;」を宣言していないと、エラーとなります。

 実行をするには、次のようにします。先ほど作成したバッチファイルを使っています。コンパイルスレッドがイベントディスパッチスレッド上で動作していることがコンソール画面へ表示され、その後に画面が表示されます。

JavaFXアプリケーションを実行
>jfx.bat SimpleFxSample.fx
compile thread: Thread[AWT-EventQueue-0,6,main]
compile 2.216
init: 1.466


図5 JavaFX Scriptで作ったサンプルの実行画面

JavaのSwingライブラリを意識したコーディングをすると?

 JavaのSwingライブラリを意識したコーディングもできます。こちらでも随分コンパクトに書けます。JavaFX Scriptの書き方に慣れないJavaプログラマはこちらの書き方の方が書きやすいかもしれません。javax.swing.JFrameなど、必要なクラスをimportしているので、忘れないようにしてください。

JavaのSwingライブラリを意識したコーディングの例
import javax.swing.JFrame;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.lang.System;

var f = new JFrame();
f.setTitle("タイトル:CallDirectSwing");
f.setSize(300, 80);
var button = new JButton("OK");
f.getContentPane().add(button);

button.addActionListener(new ActionListener() {
    operation actionPerformed(event) {
        System.out.println("OK");
    }
});

f.setLocation(200, 100);
f.setDefaultCloseOperation(f.EXIT_ON_CLOSE);
f.setVisible(true);


図6 JavaのSwingライブラリを意識して作ったサンプルの実行画面

スクリプトの起動方法を考える

 Javaプログラムとの連携を考えると、どうやってJavaプログラムからJavaFX Scriptプログラムを起動するのかについては確認をしておく必要があります。起動スクリプトから分かりますが、net.java.javafx.FXShellはmainメソッドを持っているので、次のようにmainメソッドを呼ぶのが一番簡単なようです。とはいえ、これはJavaのスクリプティング標準の方法ではありません。

FxRunner.java
import net.java.javafx.FXShell;

public class FxRunner {
    public static void main(String[] args) {
        if (args.length == 0) {
            args = new String[] {"SimpleFxSample.fx"};
        }
        try {
            FXShell.main(args);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 コンパイル時、実行時にはjavafxrt.jarや、swing-layout.jarファイルにクラスパスを通すことを忘れないようにしましょう。必要であれば、Filters.jarにもクラスパスを通します。

FxRunner.javaの実行結果
>javac -classpath ..\lib\javafxrt.jar -encoding UTF-8 FxRunner.java
>java -cp ..\lib\javafxrt.jar;..\lib\swing-layout.jar;. FxRunner
compile thread: Thread[AWT-EventQueue-0,6,main]
compile 1.903
init: 1.123

JSR-223に従うスクリプティングエンジン

 Javaスクリプティングを使って、JavaFX Scriptのエンジンを利用する前に、JSR-223に従うスクリプティングエンジンの実装がどれくらい進んでいるのかをチェックしてみましょう。次のプログラムはクラスパスに登録されているスクリプトエンジンについて、簡単な情報と、実装しているインターフェイスの一覧とを表示するプログラムです。javax.scriptパッケージに含まれるScriptEngineManagerクラスScriptEngineFactoryクラスの簡単な使用例にもなっています。

CheckEngine.java
import java.util.List;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;

public class CheckEngine {
    public static void main(String[] args) {
        ScriptEngineManager engineManager
            = new ScriptEngineManager();
        List<ScriptEngineFactory> factories = engineManager
            .getEngineFactories();
        for (ScriptEngineFactory factory : factories) {
            System.out.println(factory.getLanguageName() + ","
                + factory.getLanguageVersion() + ","
                + factory.getEngineName() + ","
                + factory.getEngineVersion());
            ScriptEngine engine = engineManager.getEngineByName(
                factory.getLanguageName());
            if (engine != null) {
                Class clazz = engine.getClass();
                System.out.println("Engine Class:"+ clazz.getName());
                System.out.println("Interfaces:");
                for (Class i : clazz.getInterfaces()) {
                    System.out.println(" "+i);
                }
            }
        }
    }
}

 これを実行すると、筆者の環境では次のように表示されました。JavaFX Script Engineに関する情報が表示されているのが分かります。なお、Mozilla RhinoJava SE 6に同梱されているECMAScript Engineです。これを見ると、Mozilla Rhinoは「javax.script.Invocable」や「javax.script.Compilable」といったインターフェイスを実装していますが、OpenJFXではこれらの実装はまだされていないということが分かります。

CheckEngine.javaの実行結果
>java -cp ..\lib\javafxrt.jar;..\lib\swing-layout.jar;. CheckEngine
ECMAScript,1.6,Mozilla Rhino,1.6 release 2
Engine Class: com.sun.script.javascript.RhinoScriptEngine
Interfaces:
interface javax.script.Invocable
interface javax.script.Compilable
FX,0.1,JavaFXEngine,0.1a
Engine Class: net.java.javafx.jsr223.JavaFXScriptEngine
Interfaces:
編集部注 Mozilla Rhinoについての詳細を知りたい読者は、連載第1回の「JavaとJavaScriptの親しい関係」をご参照願います。

JavaFX Scriptを実行するプログラム

 それでは、スクリプトを起動するプログラムを書いてみましょう。ここでは、引数については考えないで、単純に起動する方法だけ実現してみました。java.io.FileReaderクラスを使っていることから、ファイルのクローズを確実にする必要があるために、記述は長くなっていますが、ポイントはrunScriptメソッド内の処理になります。

  ここで先ほどのプログラムで得たJavaFX Scriptingのエンジン名「FX」を使って、「manager.getEngineByName("FX")」のようにScriptEngineの インスタンスを取得しています。後は、これを使って「engine.eval(reader);」としているだけです。

ScriptRunner.java(抜粋)(全ソースはこちら)
(略)

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.swing.SwingUtilities;

public class ScriptRunner {
    class ExecuteScript implements Runnable {

(略)

        private void runScript(Reader reader) {
            ScriptEngineManager manager
                = new ScriptEngineManager();
            ScriptEngine engine = manager.getEngineByName("FX");
            if (engine != null) {
                try {
                    engine.eval(reader);
                } catch (ScriptException e) {
                    e.printStackTrace();
                }

(略)

    public static void main(String[] args) {

(略)

        ScriptRunner runner = new ScriptRunner();
        SwingUtilities.invokeLater(
            runner.new ExecuteScript(fileName));
    }
}

  もう一点、注意する必要があります。最後の行でSwingUtilitiesクラスのinvokeLaterメソッドを使ってスクリプト実行のメソッドを 呼び出しています。画面を表示するプログラムはイベントディスパッチスレッドから呼び出す必要があるために、このようにしています。

 これを実行すると、JavaFX Scriptのファイルを読み込んで実行できるようになります。変数のバインドなどもJSR-223に従った方法で行えます。


アニメーションプログラムを作ってみよう

  JavaFX Scriptでは、アニメーションプログラムを簡単に作成できるということなので、それについても確認してみました。単純なデジタル時計を作成したのですが、次のようになります。

 ここでは、javafx.ui.LabelクラスextendsしたクラスとしてDigitalClockを用意しています。パッケージも使えるので、fxパッケージとして、ディレクトリfxにファイルを置いています。

JavaFX Scriptのtriggerキーワード

 JavaFX Scriptではtriggerというキーワードが あり、ある処理が発生したときに一緒に行いたい処理を記述できます。ここでは、DigitalClockの属性cについて代入がされるたびに、Dateク ラスのインスタンスを生成し、テキスト形式にフォーマットしてjavafx.ui.Labelクラスの属性textへ代入しています。

 また、コンストラクタが呼ばれたときに属性runningをtrue とし、runningがtrueの間は属性cの値を更新し続けるようにしています。ただし、「c = [1..100] dur 1000 continue if running;」という処理については、サンプルにあった処理なのですが、言語リファレンスのページであるopenjfx: The JavaFX Programming Languageには説明がないので、正確な意味は分かりません。

 dur演算子については、デモに含まれるJavaFX Canvas Tutorialに記述があります。durationの 意味で、この場合は1000ミリ秒間に10ミリ秒ごとに1から100の値がcへ代入されます。残りの「continue if running」の部分については、残念ながらそこにも説明がありませんが、動作を見る限りはrunningがtrueの間、この処理を続けることになり ます。

fx\DigitalClock.fx
package fx;

import javafx.ui.*;
import javafx.ui.canvas.*;
import java.util.Date;

public class DigitalClock extends Label {
    attribute running: Boolean;
    attribute c : Number;
}

trigger on DigitalClock.c = newValue {
    var dNow = new Date();
    text = dNow format as <<yyyy-MM-dd HH:mm:ss zzz>>;
}

trigger on new DigitalClock {
    running = true;
    c = [1..100] dur 1000 continue if running;
}

デジタル時計の起動プログラム

  これを使った画面を表示するには、次のようなプログラムを用意します。ほかのクラスと同じように、fx.DigitalClockクラスをインポートして 使っています。このクラスはjavafx.ui.Labelと同じように使えますが、インスタンスを生成すると、同時に動作し始めるので、画面を終了する ときには、停止する必要があります。それが「onClose: operation() { dc.running = false; }」の部分になります。

DigitalClockFrame.fx
import javafx.ui.*;
import javafx.ui.canvas.*;
import java.util.Date;
import fx.DigitalClock;

var dc = new DigitalClock();
Frame {
    title: "DigitalClock"
    width: 210
    height: 240
    centerOnScreen: true
    content: dc
    onClose: operation() {
        dc.running = false;
    }
    visible: true
};

図7 JavaFX Scriptによるデジタル時計の実行画面

  実行すると、デジタル時計の画面が表示されて時間を刻むのが分かるはずです。アニメーションをさせたい場合は、DigitalClock.fxの 「trigger on DigitalClock.c = newValue { /* 処理 */ }」にアニメーション用の処理を記述すればいいだけなので、それほど難しくはないはずです。Swingプログラムでは結構意識が必要だったイベントディス パッチスレッドも、それほど意識しなくてもいいようです。

デモのアニメーション

 同梱されているデモでも、オブジェクトが回転するなどのアニメーションが試せます。


図8 JavaFX Canvas TutorialデモのAnimation(実行環境はWindows XP)

RSSフィード表示アプリを作ってみよう

 最後に、インターネットアプリケーションのサンプルも作成してみました。RSSフィードを読み込んでツリー形式で表示する単純なものです。JavaFX Scriptだけでは難しいので、RomeというAtomRSS用のライブラリを使っています。RomeはJDOMを使うので、こちらも必要です。今回は、rome-0.9.jar、rome-fetcher-0.9.jar、jdom.jarを使って実装しています。

 ここでは、RssTreeというクラスを用意して、タイトルを保存する配列としてtitlesを用意し、タイトルと対になるURIを保存するマップをuriMapで用意しています。コンストラクタでフィードを読み込んで、RssTreeの初期化をしています。

JavaFX Scriptの面白い命令

 特長的なのは、while文の中でエントリからタイトルと、それに対応するURIをRssTreeへ保持する処理をしているのですが、配列のtitlesへ「insert title into titles;」という命令で値を追加している点です。配列へは添え字を使って代入するのが普通なのですが、JavaFX Scriptには、こういった面白い命令が用意されているのです。

RssTree.fx(抜粋)(全ソースはこちら
(略)

public class RssTree {
    attribute rss: String;
    attribute titles: String*;
    attribute uriMap: Map;
}

trigger on new RssTree {
    rss = "http://www.atmarkit.co.jp/rss/rss2dc.xml";

(略)

    var entries = feed.getEntries();
    uriMap = new HashMap();
    var i = 0;
    while (i < entries.size()) {
    
(略)

    insert title into titles;
    i += 1;
    }
}

var rssTree = new RssTree();

Frame {
    height: 480
    width: 600
    content: Tree {
        root: TreeCell {
            text: bind rssTree.rss
            cells: foreach (t in rssTree.titles)
            TreeCell {
                text: t
                cells: [
                    TreeCell {
                        text: rssTree.uriMap.get(t).toString()
                    }
                ]
            }
        } // TreeCell
    } // Tree
    visible: true
}

JavaFX Scriptのforeach文

 rootのTreeCellへTreeCellを追加するに当たり、foreach文を使って登録しているあたりにも注目してください。こういった処理は癖があるので慣れるまで難しいと思いますが、同じ部品を繰り返し登録するのには便利です。

RSSフィード表示アプリの実行結果

 実行時にはRomeとJDOMのJARファイルへもクラスパスを通すように気を付けてください。起動に成功すると、@ITのフィードを読み込んで表示します。エラー処理については記述していませんが、このようなプログラムも組めることが分かりました。


図9 JavaFX ScriptによるRSSフィード表示アプリの実行画面

JavaFX Scriptを楽しむ

  以上、ドキュメントが少ない中、インターネット上で公開されているサンプルと、ダウンロードしたアーカイブに同梱されているデモプログラムを中心にして簡 単なサンプルを作ってみましたが、本格的に使用するには、まだいろいろと苦労しそうですが、面白いプログラミング言語だと思いました。

 最後にコンポーネントを組み合わせて表示するプログラム(ソースはこちら)も作成してみましたが、複雑なデザインの画面も結構気軽に作成できそうです。


図10 ComponentTest.fxの実行画面

RIAの元祖はJavaアプレットだった

 思い起こせば、10年前にJavaアプレットという方法で、RIAを実現する言語としてJavaには注目していましたが、いろいろな経緯を経て、あまり使われなくなってしまいました。最近はJavaのプラグインが必要なサイトはほとんど見掛けません。

 Swing も高性能なのですが、なかなかデスクトップサイドのアプリケーションで普及しているものはありません。筆者はかなりJava好きですが、Webブラウザ、 メールクライアント、オフィス製品など、どれもJavaアプリケーションのものは使っていません。しかし、Sunはあきらめていなかったのでしょう。ここ にきて、JavaFX Scriptでこの分野での巻き返しをしようとしているのではないでしょうか。まだまだ実力は未知数ですが、言語としては面白い機能を持っているので、楽 しめることは間違いありません。

Java SEと親和性のあるRIA

 また、Javaには既存の膨大なライブラリがあり、JavaFX Scriptからは、それらを簡単に使えるという点は大きな魅力です。Java SEのアプリケーションやライブラリと親和性のあるスクリプト言語は、必ず開発に役立つはずです。

 ただし、JavaFX Scriptは、高度なアニメーション機能を備えたGUIインターフェイスの開発を容易にすることに重点が置かれていますから、その点だけは忘れないようにした方がいいでしょう。以上の事柄を踏まえて、JavaFX Scriptを新しい開発に生かしていくといいのではないでしょうか。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值