人生、気合いと具合 - blog

この記事は、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だけで行けるのでは?と思ったから。
というか本当はそこまで試したかったんだけど、時間切れなのでこの辺で。

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

9/6、7の2日間、Scala Matsuri 2014に参加してきました。

1日目のセッションの内容については、公式サイトのプログラムのページにリンクがあるようです。
まだ少なめですけど、たぶん増えていくのでは。

また、ニコ生でも中継されたので、アーカイブが見れます。
(有料会員じゃないとダメかも?)


2日目のアンカンファレンス、どんな感じなのか若干不安もあったんですが、思いのほかお気楽な感じで、すごく楽しめました。
朝一からアルコール入れてしまったのでテンション高めでしたが、体力的に最後まで持たず、途中退場してしまいました。(と言っても、たしか当初の終了時刻だったはず)
もう少しペースを考えようw

2014/8/22(金)のJJUGナイトセミナーで、「Skinny Frameworkを使ってみました」というタイトルでLTしてきました。

5分、しかも実際のアプリの画面を見せながらの発表だったので、資料だけだとどうだろうという感じですが。

で、LTは(ちょっと時間が足りなかったとはいえ)悪くはなかったと思うんだけど、結局呑み過ぎてしまったので反省。

このページのトップヘ