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)))