2012年2月2日木曜日

ClojureとFXML

JavaFX for Linux キタ━(゚∀゚)━!
ということでさわってみました。

ただ動かすのも面白くない、というかJava面白くない、ということでClojureから呼び出してみました。

JavaFXで私が一番注目していたものはFXML。
XMLは好きじゃないけど、ちゃんとロジックが分離できそうだし、GWTのUiBinderを気に入っていたので楽しみにしていました。

というわけでClojure+FXMLで書いてみました。

プロジェクトの設定(Linux)

Leiningenを使います。

多分Winの場合はそのまま動く。
Linuxの場合は http://www.oracle.com/technetwork/java/javafx/downloads/devpreview-1429449.html から Linux 32-bit をダウンロードして、 lib に jfxrt.jar を、 bin に *.so を置いて下さい。

main.clj

まずはApplicationを継承した起動ポイントを書く。


main/launchだとエラーが出る謎。

pane.clj

xmlをFXMLLoaderでロードするだけ。


root.xml

fx:controllerを指定してButtonを置いてonActionを設定する。


controller.clj

Buttonから呼び出される関数を定義する。


gen-classに:methodsをわざわざ書くのがめんどう。

実行



なんかあっさり動いてしまった。

これでバリバリClojureでGUIが書けるぞー










と思ったらそんなことなかった。

fx:id

Buttonを押したらLabelのテキストが変わるようにしてみたい。
そんな場合はfx:idでControlに名前をつけるとコントローラで扱えるようになる。
その時にコントローラはmutableFXMLアノテーションが付いたフィールドを持っていなければならない。

gen-classでフィールドは指定できない。
Clojureでは:stateを使うことで状態を実現している。

一番最初に思いついたものはdeftypeを使う方法。

deftype

deftypeではmutableなフィールドを持てます。
なのでdeftypeでコントローラを作ってみます。


でもこれだと、コンストラクタが引数をとるのでFXMLLoaderがインスタンスを作れない。
なのでこれを更に継承・・・・・出来なかった。
なぜならdeftypeで作ったクラスはfinalが修飾されている。
メソッドの型も曖昧なままなので継承できたとしても動くかどうかはわからない。

こうなると別の方法を取るしかないですね。

別の方法といってもClojureでclassを作るにはdeftype, defrecord, gen-classしかない。
deftypeは先程の通りコンストラクタが引数をとってしまう。
defrecordではそもそもmutableなフィールドを持てない。
gen-classはフィールドを指定できない。

Javaを使うことを・・・強いられてるんだ!

ここで登場Java!
嫌いじゃないけど使いたくないJava!

Java側でmutableでFXMLアノテーションが付いた変数を宣言しておこうという戦略。


これを継承してさあ実行。


javafx.fxml.LoadException: Value is already set.


\(^o^)/

ヤンナルネ・・・・・

結果

onActionで関数を指定して呼び出すことはできたがfx:idが使えなかった。

誰か解決方法があったら教えて下さい!

※追記

javafx.fxml.LoadExceptionは別のところでした・・・
しかし、結果は変わらず。

FXML側で実行すると、エラーが握りつぶされてしまうのですね。

※※追記

解決しました!

0 件のコメント:

コメントを投稿