Clojureでjavax.swing.JFrameを使ってみる
Clojureからjavax.swingを使い、GUIプログラミングをかじり始めつつ、Javaのメソッド呼び出しのやり方も練習もする。
Javaメソッドの呼び出し方
例えば、文字列Helloの長さを返す。
repl=> (.length "Hello") 5
これはJavaで"Hello".length()を呼びだしたと同じ。
staticメソッドを呼び出す
repl=> (java.lang.Math/abs -1) 1
これはそのままで分かりやすい。
デフォルトの状態でjava.langはnamespaceにはimport済みのようなので、下記も同様の動きをする。
repl=> (Math/abs -1) 1
JFrameを使ってウィンドウを出す
いつものとおり、leinで新しいプロジェクトを作って試す。
swing $lein new app hello_frame
単純に400x400の大きさのフレームを出してみる。
以下ソース。
(ns hello-frame.core (import (javax.swing JFrame)) (:gen-class)) (def frame (new JFrame)) (defn -main [& args] (.setSize frame 400 400) (.setTitle frame "Hello,JFrame") (.setVisible frame true))
JFrameのインスタンスは(new Frame)で生成し、以降(.setSize ...)などでメソッド呼び出しをしている。
(.setSize frame 400 400)とかは、実はマクロを使っていて、内部的にはドットスペシャルフォームに変換される。(.を使った特殊形式)
macroexpand-1を使って展開してみると、以下のようになる。
repl=> (macroexpand-1 '(.setSize frame 400 400)) (. frame setSize 400 400)
逆に言うと、.特殊フォームを使っても書ける訳で、下記も同じ動作をする。
(ns hello-frame.core (import (javax.swing JFrame)) (:gen-class)) (def frame (new JFrame)) (defn -main [& args] (. frame setSize 400 400) (. frame setTitle "Hello,JFrame") (. frame setVisible true))
こっちの方が分かりやすいよな。と個人的に思ったが・・・。
さて、Javaのクラスのインスタンスを作るのは
(new JFrame)でできるが、こちらは(JFrame.)という表記でも可。
引数も与えることができて、
(JFrame. "Heeloooo")とするとタイトルの文字列を与えてインスタンス生成する。
同じオブジェクトのメソッドを連続して呼び出したい時に、便利なマクロdotoが用意されている。
今回の場合では、frameに対して、setSize、setTitle、setVisibleを呼びたい。以下のように書ける。
(doto frame (.setSize 400 400) (.setTitle "Hello,JFrame") (.setVisible true)))
うむ、便利。
とりあえず、JFrameをnewするときにタイトルも渡すようにすると、最終ソースは下記のようになる。
(ns hello-frame.core3 (import (javax.swing JFrame)) (:gen-class)) (def frame (JFrame. "Heeellooo!!")) (defn -main [& args] (doto frame (.setSize 400 400) (.setVisible true)))