読者です 読者をやめる 読者になる 読者になる

不確定特異点

広く深く、ところどころ超深く

LTK でウィンドウを手前に表示する

LTK とは Tk ツールキットを Common Lisp から使えるようにしたものです。Tcl/Tk をベースにしているため、幅広い OS に対応していることや手軽に UI を作成できることが魅力です。Common Lisp でちょっとした GUI を作りたいときにも便利そうですね。

LTK を使うには Tcl/Tk 付属の wish コマンドが使えればよく、Common Lisp ライブラリのインストールは Quicklisp から LTK を ql:quickload するだけですみます。

CL-USER> (ql:quickload :ltk)
To load "ltk":
  Load 1 ASDF system:
    ltk
; Loading "ltk"

(:LTK)

LTK には ltktest というサンプルプログラムが付属しており、以下のように試すことができます。また、ltktest のように export はされてませんが、ソースコードの中には ltk-eyes という xeyes 的なサンプルプログラムもありました。

CL-USER> (ltk:ltktest)
CL-USER> (ltk::ltk-eyes)

ところで上記のサンプルを動かしてみるとわかるのですが、LTK を実行して起動したウィンドウが手前に表示されないため、インタラクティブに UI を組み立てていくことが面倒です。これは別に LTK に限った話ではなく、wish でも同様の動作になるのですが、なんとかウィンドウを手前に持ってきたいので調べてみると、wish では次のようにすれば良いことがわかりました。

wm attribute . -topmost 1

しかし、LTK のドキュメントを見る限り、これに相当する直接的な API は存在しないようでした。そこで、LTK のコードを眺めてみると、LTK は実際には内部的に wish を起動し、format-wish という関数により、ストリーム経由で Tcl コマンドを wish に送ることで GUI を作る、という仕組みのようでした(たぶん)。というわけで、format-wish を使って上記の Tcl コマンドを送ることで LTK でも同じ効果が得られないか、実験してみました。

(defun main ()
  (ltk:with-ltk ()
    (let* ((b (make-instance 'ltk:button
                             :master nil
                             :text "hello"
                             :command #'(lambda () (format t "hello, world!~%"))))
           (c (ltk:make-canvas nil :width 200 :height 150))
           (r (ltk:create-rectangle c 20 20 100 100)))
      (ltk:itemconfigure c r "fill" "black")
      (ltk:pack c)
      (ltk:pack b)
      (ltk:format-wish "wm attribute . -topmost 1"))))

単なるサンプルとして UI を並べているだけなのでプログラム的にはあまり意味はありません(キャンバスとボタンがあって、キャンバスに四角をお絵描きするだけです)が、最終行にあるように format-wish により wm attribute . -topmost 1 を実行してあげると、期待通りウィンドウが手前に表示されました!

f:id:tanakahx:20151020234953p:plain

format-wish を使えば任意の Tcl コマンドを wish に投げられるので、これ以外にも、LTK の API として提供されていないような細かな設定が色々できると思います。

以下の記事を参考にさせて頂きました。