人生、気合いと具合 - blog

2014年12月

この記事は、しょぼちむ Advent Calendar 2014 の20日目の記事になるはずでした。

19日目は @setoazusa さんの しょぼちむにテストファーストについて説明してみる でした。
21日目は @seri_k さんの 若者と転職 です。 

 そんなわけで、残念ながら間に合わなかった記事でございます。なぜかって?SIerだからさ!

しょぼちむといえばやはり目の前で見た、某雪だるま氏へのくんかくんかが最も記憶に残っています。ってことで(?)、ScalaFXを使ったミニゲームです。 

画面に出てくる雪だるまをタッチするとロックオン、画面下でうろうろしているレッドキングにタッチするとくんかくんかします。(タッチパネルじゃない場合はマウスクリックでも動きます)
複数まとめてロックオンしてからくんかくんかすると高得点。約1分間でどれだけくんかくんかできるかを競います?(なんのこっちゃ)

ダウンロード:http://homepage2.nifty.com/bugworm/webapp/syobo/AdventCalendar2014.jar
 
Java 8 + Scala2.11 + ScalaFXを使用。動作はJava 8だけあればOKだと思います。

kunka




























この記事は、JavaFX Advent Calendar 2014 の14日目の記事です。

昨日は @peko_kun さんの DataFXでFlow でした。
明日は @suzukij さんです。

Javaでは、Java SE 6から、スクリプト言語の実行を標準化した仕様が取り入れられています。
まずはこれで、JavaとJavaScriptを連携させてみましょう。

package sample;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class JSCall {
    public static void main(String... args)throws Exception{
        ScriptEngineManager man = new ScriptEngineManager();
        ScriptEngine engine = man.getEngineByName("nashorn");
        engine.eval("Java.type('sample.JSCall').callback('実行した!');");
    }
    public static void callback(String message){
        System.out.println(message);
    }
}

ScriptEngineのevalメソッドで、JavaからJavaScriptを実行できます。
そして、JavaScriptでは、Java.typeを使ってクラス名を指定、そのままスタティックメソッドを実行できます。
そんなわけで、とりあえずJavaからJavaScript、JavaScriptからJava、両方実行できることはわかりました。

さてJavaFXにはjavafx.scene.web.WebEngineというクラスがあり、こちらでもJavaScriptを実行することができます。要はブラウザのJavaScriptを実行するわけですね。
ところが、WebEngineのexecuteScriptで先程と同じようにやってみると、「Java」なんて変数は無いよー、ということでエラーになってしまいます。
Java.typeが使えないというわけですが、ブラウザのJavaScript環境で任意のJavaクラスにアクセスできたら危険過ぎるから、ってことでしょうかね?

ではJavaScriptからJavaへ連携する方法がないのかというと、いくつかあるset~Handlerメソッドでコールバックを受けることができます。
たとえば、setPromptHandlerを使ってみましょう。
以下はJavaFXのコントローラークラスです。画面にはテキストフィールドとボタンがある感じですね。

package sample;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TextField;
import javafx.scene.web.WebEngine;

import java.net.URL;
import java.util.ResourceBundle;

public class Controller implements Initializable{
    public TextField text;
    public WebEngine engine = new WebEngine();

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        engine.setPromptHandler(data -> {
            System.out.println(data.getMessage());
            return "";
        });
    }

    public void buttonAction(ActionEvent actionEvent) {
        engine.executeScript("prompt('" + text.getText() + "');");
    }
}

ブラウザとして使うわけではないので、WebEngineはインスタンス化の際にnewしています。
初期化時に、WebEngineのsetPromptHandlerで、コールバック関数というかコールバックラムダ?を設定しています。(インタフェースとしては、Callback<PromptData,String>)
あとは、ボタンが押されたらexecuteScriptにprompt関数を実行するJavaScriptを渡してやります。すると、設定しておいたコールバックが実行されるという流れですね。

このしくみを使えば、JavaFXのアプリでブラウザのJavaScriptと(ある程度)やり取りができますね!


ちなみに、これを調べたきっかけは、WebSocketで遊んでた時です。
クライアント側をJavaFX作るとした場合、もちろんWebSocketのクライアント用JavaAPIがあるのでそれでもいいのですが、WebEngineのJavaScriptと連携できれば素のJava SEだけで行けるのでは?と思ったから。
というか本当はそこまで試したかったんだけど、時間切れなのでこの辺で。

俺、今のプロジェクトの炎上がおさまったらこの続編としてやってみるんだ...(フラグ!?)

このページのトップヘ