Programmer's Note

コード読み書きの備忘録。

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に対して、setSizesetTitlesetVisibleを呼びたい。以下のように書ける。

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

参考文献

Working with the JVM | Clojure for the Brave and True