Rhino/SWT - JavaScript でネイティブな GUI アプリを作る

JavaScript (ECMAScript) から SWT を呼んで、Windows 用のスタンドアロンアプリを作ってみた。
とりあえず Hello World っぽいのはこんな感じ。ボタンを押すとメッセージボックスが出る。


スクリプトはこうなった。とりあえず、SWT むき出し。

var d = Display.getDefault();
	
var s = new Shell(d, SWT.TITLE | SWT.CLOSE | SWT.BORDER | SWT.RESIZE);
s.text = "Hello Rhino";
s.setLayout(new FillLayout());
s.setSize(100, 70);

var b = new Button(s, SWT.NONE);
b.text = "button!!";
b.addSelectionListener(function(event) {
	var m = new MessageBox(s);
	m.message = "!!!";
	m.open();
});
s.open();
		
while (!s.disposed) {
	if (!d.readAndDispatch()) {
		d.sleep();
	}
}
		
d.dispose();

作り方

実装の仕方はいろいろ考えられるけど、今回は「exe をクリックすると、同じディレクトリで同じ名前の js ファイルが実行される」というスタイルにした。使ったのは、以下のもの。

JDK or JRE
http://java.sun.com/
SWT
http://www.eclipse.org/swt/
Rhino
http://www.mozilla.org/rhino/
exewrap
http://www.ne.jp/asahi/web/ryo/exewrap/

あとは、Rhinoスクリプトファイルを読ませる Java クラスがあればいい。基本的にはサンプルの RunScript まんま。
今回は、トップレベルのオブジェクトとして ImporterTopLevel を使用し、Java クラスの側で SWT のパッケージを全部インポートした。上に載せたスクリプトSWT のクラスをいきなり使えてるのはそのため。

作ってみて

手間はとにかくかからなかった。今回 Java で書いたコードはわずか 85 行 (コメントと空行を含む)。SWT の操作については、Rhino がリフレクションでうまくやってくれる。例外処理についても、exewrap のログ出力機能にお任せ。
上のスクリプトでは、イベントリスナを渡すべきところに Function を渡している。これでできちゃうのは、Rhino にそういう機能があるからだ (Rhino のドキュメントに解説がある)。
一方、オブジェクトのプロパティについては、ちぐはぐになっている部分もある。例えば Shell のプロパティについて

s.text = "Hello Rhino";

はできるのに、

s.layout = new FillLayout();

と書くとエラーになるため、

s.setLayout(new FillLayout());

と書かなければならない。原因は、Shell には layout() というメソッドがあって、Rhino はそちらを優先するから。

他の実装方法

例えば、D 言語で、DScript/DWT という実装ができそう。他の言語で作るなら、SpiderMonkey と適当な GUI ツールキットを組み合わせるのもありだろう。
ただしこれらの場合は、Java のようなリフレクションが使えないので、自前でブリッジを用意する必要がある。
すでにある実装例としては、MozillaXULRunner がある。