レガシーコード生産ガイド

私に教えられることなら

SBCL / Linux Mint でGUI (Ltk, cells-gtk)

なんとなく、HTML5ばっかじゃなくてネイティブのGUI触る方法も知っておこうかなと思ったので調べてみた。

方針

  • 日本語の表示と入力を試す
  • fcitxとMozcを使う。IME周りよくわからないので問題おきたらそこで断念する(と思う)
  • quicklispで簡単に使えないものも飛ばす

Ltk

参考にしたのは以下のサイト

まずインストール。

CL-USER> (ql:quickload :ltk)
To load "ltk":
  Install 1 Quicklisp release:
    ltk
; Fetching #<URL "http://beta.quicklisp.org/archive/ltk/2015-01-13/ltk-20150113-http.tgz">
; 60.51KB
==================================================
61,963 bytes in 0.28 seconds (218.45KB/sec)
; Loading "ltk"
[package ltk].....................................
[package ltk-user]................................
........
(:LTK)

参考サイトに書かれてるように、以下のコードを評価するとwishが無いと言われる

CL-USER> (use-package :ltk)
T
CL-USER> (with-ltk ()
      (wm-title *tk* "こんにちは、GUI")
      (minsize *tk* 400 300)
      (maxsize *tk* 400 300)
      t)
;; Couldn't execute "wish": そのようなファイルやディレクトリはありません

tclもインストールするんだっけ?と迷ったけど、wish実行してみるとtkをインストールすればいいと表示されたのでインストール。

sudo apt-get install tk

再度実行するとウインドウが表示された。日本語の表示も大丈夫みたいだ。

f:id:phaendal:20150321173524p:plain

入力はどうだろう?Tcl/Tkの解説を見ると、entryがウィジェットみたいだ。で、それをどうやって貼るんだろう?Ltkのexampleを見てみる。

(defun main ()
  (setf *debug-tk* nil)
  (with-ltk ()
    (let ((b (make-instance
              'button
              :text "Hello World!"
              :command (lambda ()
                         (do-msg "Bye!" "Hello World!")
                         (setf *exit-mainloop* t)))))
      (pack b))))

この'button'entryに変えればいいかな?やってみよう。

(defun main ()
  (setf *debug-tk* nil)
  (with-ltk ()
    (let ((e (make-instance
              'entry)))
      (pack b))))

f:id:phaendal:20150321174907p:plain

変換ウィンドウの表示位置も大丈夫だった。

最後に、entryの内容をbuttonのラベルにしてみる。ついでに、buttonの:commandではなくbindを使ってみる。

(defun main ()
  (setf *debug-tk* nil)
  (with-ltk ()
    (let ((ent (make-instance 'entry))
          (btn (make-instance 'button
                              :text "get")))
      (pack ent)      
      (pack btn)
      (bind btn "<ButtonRelease-1>"
            (lambda (e)
              (declare (ignore e))
              (setf (text btn) (text ent))))
      )))

結果

f:id:phaendal:20150321175934p:plain

おー、全然問題無い。いいね!

コンパイルしたものを配布するのはちょっと面倒なのかな。普段ちょっとしたものを作るにはかなり良さそう。

cells-gtk

Cellsというものを使ったgtk操作ライブラリらしい。

Cellsってなんだろう?

Think of the slots as cells in a spreadsheet

なるほど、バインディングとかリアクティブとか言えばいいのかな、CLOSで宣言的にプログラミングするためのライブラリみたいだ。

さっそくcells-gtkをインストールしてみる。cellsはインストールしたことないけど、自動的に解決シてくれるかな?と(ql:quickload :cells-gtk)したら、自動的に入れてくれた。便利だなあ。しかし、cl-glutのインストールでlibglut.soかlibglut.so.3が無いとエラーが出た。ので、次の順番で実行するのが安全だ。(余談だけど、初めてCLのデバッガのRetryの恩恵を受けた。)

sudo apt-get install freeglut3

SBCLのREPLにて

(ql:quickload :cells-gtk)

とりあえず日本語タイトルのウインドウを表示してみる。gitリポジトリのソースを適当に眺めて書いて実行。

(defpackage :hello
  (:use :common-lisp :cells :gtk-ffi :cells-gtk)
  (:export start-hello))

(in-package :hello)

(defmodel hello (gtk-app)
  ()
  (:default-initargs
      :title "こんにちわ"
    :position :center
    :width 200 :height 200))

(defun start-hello (&optional dbg)
  (cells-gtk-init)
  (cells-gtk:start-app 'hello::hello :debug dbg))

cells-gtkをquickloadしたREPLで(hello:start-hello)すると

f:id:phaendal:20150321192922p:plain

表示できた。

entryを表示して日本語を入力してみる。

(defmodel hello (gtk-app)
  ()
  (:default-initargs
      :title "こんにちわ"
    :position :center
    :width 200 :height 200
    :kids (c? (the-kids
               (mk-vbox :kids
                        (list
                         (mk-entry :md-name :myentry)
                         (mk-hseparator)
                         (mk-button :label "get!")
                       ))))))

f:id:phaendal:20150321194921p:plain

上手くSSとれないんだけど、変換ウインドウの位置はちゃんと合ってるし、Tkと違ってインライン入力・変換もできる。これはGtk使ってるなら全部なのかな?

これもボタンを押したらボタンのラベルがentryの内容になるようにしようと思ったんだけど、

  • ボタンのラベルをセットしなおす方法がわからない
  • ボタンのラベルとmyentryをバインドすると無限ループになる

ので断念してlabelにバインドしてみた。

(defmodel hello (gtk-app)
  ()
  (:default-initargs
      :title "こんにちわ"
    :position :center
    :width 200 :height 200
    :kids (c? (the-kids
               (mk-vbox :kids
                        (list
                         (mk-entry :md-name :myentry :auto-update t)
                         (mk-hseparator)
                         (mk-label :markup (c? (with-markup () (widget-value :myentry ""))))
                       ))))))

f:id:phaendal:20150321202812p:plain

テキスト入力に合わせて自動的にラベルも変わる。とりあえず日本語の入力・表示・扱い全て大丈夫みたいだ。

ウィジェットの内容を変化させたりはCellsについて詳しく調べないといけないのかな。

Cellsと併せて、中〜大規模なGUIを作るのにはいいのかもしれないと思った。しかしドキュメントが見当たらないので辛そうだ。

感想

  • Ltk楽だな〜
  • 次はMcCLIMとか触ってみよう。
広告を非表示にする