Groovy
JavaFX
ScriptEngine
JavaFXDay 5

JavaFX と ScriptEngine を組み合わせた学習用アプリケーションを作る

More than 1 year has passed since last update.

この記事は JavaFX Advent Calendar 2015 の 5日目の記事です。

昨日の4日目は skrb さんの「Wheel or Touch」です。明日の6日目は bitter_fox さんです。


挨拶

はじめまして、トースト小僧と申します。今回を機にQiitaを始めました。よろしくお願いします。


自己紹介

Java で GUI アプリケーションを作るのが趣味です。インターネット系企業でプログラマーをやっています。会社では Storm Trident を使ったバックエンドのシステムや API や Android アプリを作っています。


概要

この記事では JavaFX と ScriptEngine を組み合わせて、プログラミング言語の学習に使えるツールを作る過程を紹介します。


ScriptEngine

Java からスクリプト言語を動かすための仕組みで、デフォルトでは JavaScript がサポートされています。ほか、Groovy や Jython, JRuby, Scala 等も実装されているようです。

今回はGroovyとJythonを実装してみます。


依存の追加

build.gradle の dependencies に下記を追加します。


dependencies

compile 'org.codehaus.groovy:groovy-all:2.4.5'

compile 'org.python:jython-standalone:2.7.0'


ScriptEngine の取得

各言語のScriptEngineオブジェクトは下記の通り取得します。

final ScriptEngine python = new PyScriptEngineFactory().getScriptEngine();

final ScriptEngine groovy = new GroovyScriptEngineFactory().getScriptEngine();

ちなみに JavaScript は標準で用意されていて、下記で取得できます。

final ScriptEngine js = new ScriptEngineManager().getEngineByName("javascript");


標準入出力のリダイレクト

通常、ScriptEngineを使って実行したコードのログ・エラー出力は標準入出力にされます。JavaFXのアプリケーション上でこれを表示したい場合はリダイレクトする必要があります。

今回はStringWriterを使ってStringBuilderに処理結果を入れます。

final StringBuilder result = new StringBuilder();

final StringWriter writer = new StringWriter();

try {
if (python != null) {
final ScriptContext context = python.getContext();
context.setWriter(new PrintWriter(writer));
context.setErrorWriter(new PrintWriter(writer));
}
if (groovy != null) {
final ScriptContext context = groovy.getContext();
context.setWriter(new PrintWriter(writer));
context.setErrorWriter(new PrintWriter(writer));
}

final java.lang.Object run = js.eval(script);
result.append(writer.toString()).append(System.lineSeparator());
if (run != null) {
result.append("return = ").append(run.toString());
}
writer.close();
}

……


JavaFX成分

左側のTextAreaにスクリプトコードを入力し、右側のTextAreaで実行結果を表示します。それだけです。もう(別にJavaFXじゃなくて)いいじゃん……

final String result = func.runScript(scripterInput.getText(), lang).get();

if (StringUtils.isEmpty(result)) {
return;
}
scripterOutput.setText(result);


試す

advent2015_1.png

起動するとこんな感じです。

advent2015_2.png

左側のTextAreaに、適当にスクリプトを打ち込んでみましょう。

advent2015_3.png

run ボタンを押すかctrl+enterでスクリプトが実行され、その結果が右側のTextAreaに表示されます。

めでたしめでたし……



おまけ

CSS を切り替える機能をつけてみました。

advent2015_4.png

詳しくはソースコードをご覧ください。

こんな感じで用意した CSS を下記のように適用すればOKです。

final ObservableList<String> stylesheets = thisStage.getScene().getStylesheets();

// 前回適用した内容をクリア.
if (stylesheets != null) {
stylesheets.clear();
}
Application.setUserAgentStylesheet("MODENA");
stylesheets.add("path/to/css");


GitHub repository

javafx_advent2015