ClojureでGUIアプリを作ってみた。

Posted by YpsilonTAKAI On 2011年12月5日月曜日 0 コメント

この記事は、Clojure Advent Calendar 2011の5日目の記事です。

Clojure界隈では、というより他でもWeb系のいろいろが沢山なわけですが、仕事がそっち系でないのでそういう指向があまりないのです。
Clojureは今のところ趣味で、主にProject Eulerとか解くのに使っているわけですが、以前、デスクトップアプリ作ってみたのでその時のことを。



環境
---------------------------------------
- マシン
自宅ではLinux機メインでやってますけど、仕事ではWin機です。

- エディタ
いつもはエディタとしてxyzzyを使っているのですが、Clojureを使うには環境があまり整備されていないし(自分でなんとかしろ?ですよねぇ。)、ClojureBoxってのがあるようなので、入れちゃうことにしました。

でも、もうメンテされていないので、1.3.0にしたければ自分でやることになります。 あまり手間もかからないとは思いますけど、そろそろ自分で一から環境作ってもいいかなと思ってます。

- shell
Leiningen使うにはコマンドラインを使うのですが、Winのcommand.comはとても使えたものじゃありません。cygwinとかmsysとか入れたらいいんでしょうけど、それはちょっとだったので、PowerShell使うことにしました。PowerShellが入っていなかったので入れました。

emacsからPowerShellを使いたいので、PowerShell-modeをここを読んで入れました
設定して起動したらと、"unrecognized shell program" って怒られます。特に問題無く動くんのでしばらく無視してたんですが、やっぱり気になって調べてみたら、ClojureBox/emacs/emacs/lisp/shell.el で出しているメッセージで、コーディングシステムを設定しているところでした。
command.comと同じ設定でいいだろうということで、PowerShell用の設定を追加して黙らせました。


587行目あたり

(cond ((w32-shell-dos-semantics) (set-process-coding-system proc cp-out-dos cp-in-unix)) ((string-match "/msys/" fullprog) (message "think it is MSYS...") (set-process-coding-system proc cp-locale-dos cp-locale-unix)) ((string-match "/cygwin/" fullprog) (message "think it is Cygwin...") (set-process-coding-system proc cp-locale-dos cp-locale-unix)) ;; 以下3行追加。 ((string-match "powershell.exe" fullprog) (message "think it is Powershell...") (set-process-coding-system proc cp-out-dos cp-in-unix)) (t (message "unrecognized shell program yosi: %s" fullprog)))))))

準備
---------------------------------------
- GUIツール
これまでJavaとか華麗にスルーして生きてきて、つい最近androidのアプリが作りたくて初めて触ったような人なので、awtとかswingとかちんぷんかんぷん。とてもそのままでは作れる気がしません。で、ちょっと調べてみたらよさそうなのがあるではないですか。

seesaw
Seesaw is a library/DSL for constructing user interfaces in Clojure. It happens to be built on Swing, but please don't hold that against it.
SeesawはUIを作るためのライブラリー/DSLで、Swingの上に構築されていますが、Swingがだめだというわけではありません。

メイン
https://github.com/daveray/seesaw

使いかた
https://github.com/daveray/seesaw/wiki


-プロジェクトの作成
1. Leiningenで新しいプロジェクトを作ります。
 lein new guitest
 cd guitest

2. project.cljを編集してseesawを追加します。

(defproject guitest "1.0"
  :description "Seesaw test project, and more."
  :dependencies [[org.clojure/clojure "1.2.1"]
[org.clojure/clojure-contrib "1.2.0"]
[seesaw "1.0.7"]]                        ;; 作ったときはこれが最新だった。
  :main guitest.core)                             ;; スタンドアロンにするにはこれが要る。


これで準備は終り。


作成
---------------------------------------
「画像処理おもしろそう」と思って作ったアプリがあるのでこれについて。
GUIが目的ではないので見た目とか適当です(なんのこっちゃ)。

  ★★
  って書いておいて、動かしてみたら動かない。
  処理を早くしようとか、保存できるようにとかしてる途中だったみたいです。
  次の番が回ってくるまでに動くようにしときます。*_*;;;;;;

  動いていたときの画像。




- ソース (github)
https://github.com/ypsilon-takai/clojure-seesaw-test001

苦しまぎれに、解説なんかを。 いや、自分用に...
こうした方がいいんじゃない?ってなことがあれば、ご指摘いただけるとうれしいです。


core.clj
----------------------
 UI部分。画像の読み込みと表示。
 画像処理部分は、別ファイル (imagetool.clj)

14行目
 * 元画像BufferedImage と 表示用画像BufferedImage と 画像処理用long-array など
   書き換えるのでmutableなデータになってます。

23-38行目
 * 入力画像の選択/結果の出力ダイアログ。
   seesawのダイアログを使ってるだけ。

43-78行目
 * 新しい画像を読み込んだときの処理関数たち。
   下の2つが、新しいデータを作る関数と、データを再表示する関数。

81-87行目
 * 画像を保存する関数たち。

91-140行目
 * 画像処理関連
   配列からBufferedImageを作る関数。
   グレースケール化とエッジ検出の処理を呼ぶ関数。

141行目からGUI関連

147-216行目
 * 各ボタンの定義。 actionはそのためのseesawの関数(マクロ?)です。
   押されたときの関数を定義したり、ボタンに表示される文字列を設定したりします。
   Clojure流に設定できるので、気持いいです。

218行目
 * ウィンドウの定義です。
   実行すると、ウィンドウのフレームを返します。
   :content で中を定義します。
   これもClojure流に設定できます。

248行目
 * このクラスのメイン関数です。
   projectファイルでこのファイルをmainとしているので、jarを実行したときに、この-main関数が呼ばれます。
   native! を呼んでおくと、見た目がプラットフォームのものになるそうな。
   上で定義したmain-windowに show!してやると表示されます。




imagetool.clj
----------------------
前半はたいしたことやっていないので割愛。

72行目からがエッジ検出のところです。
いくつかの種類のフィルタを使えるようにしてあります。

create-operationは、フィルタを与えると、どうすればいいかを返します。

transform-to-edge-imgは、画像のデータの入った配列と変換の種類を受け取って、変換後の配列を返します。

0 コメント:

コメントを投稿