LablGTK で遊ぶ

LablGTK(http://wwwfun.kurims.kyoto-u.ac.jp/soft/lsl/lablgtk.html) は、OCaml のための GUI ライブラリです。素敵です。

背景

  • 研究のためにサンプルプログラムを書く必要があった
  • マルチスレッドと GUI のライブラリが必要だった
  • Haskell + wxHaskell でやってたけど、うまくいかなかった(たぶん僕のミス)
  • じゃあ(嫌だ力を発揮して) OCaml でやってみるか
  • 普通に動いたバロス

インストール

  • Mac: MacPorts でインストールでき、コンパイルもできますが、ウィンドウが表示されません。頑張れば動くような感じ。
  • Linux: Ubuntu なら aptitude でインストールでき、動作もかんぺき
  • Windows: わかりません

ドキュメント

公式のドキュメントはLablGTKにあります。あとは、http://alohakun.blog7.fc2.com/blog-entry-579.htmlからリンクをたどって参考にしました。いくつかサンプルを見て、あとは公式のドキュメントを睨めばなんとかなる。

ソースコード

やんごとなき事情により、研究用に書いたコードは事情を知らない人にはとっても読みにくいことに今気がついた。
でもここまで書いたのにざっくり消すのは悲しいので、とりあえず簡単なアプリケーションを書いてみた。

ボタンを交互に押し込むだけのもぐらたたきアプリケーションだ!

open Event
open GMain

let change_availavility obj b = obj#misc#set_sensitive b;;
let set_disable obj = change_availavility obj false;;
let set_enable obj = change_availavility obj true;;

let main _ = 
  (* レイアウト設定 *)
  let window = GWindow.window ~border_width:5 ~title: "mogura-tataki" () in
  let layout = GPack.vbox ~spacing:5 ~packing:window#add () in
  let text = GEdit.entry ~editable:false ~packing:layout#add () in
  let buttons = GPack.hbox ~packing:layout#add () in
  let mogura1 = GButton.button ~label:"(*-*)" ~packing:buttons#add () in
  let mogura2 = GButton.button ~label:"(*-*)" ~packing:buttons#add () in
    text#set_text "COUNT: 0";
    set_disable mogura2;

    let count = ref 0 in
    (* イベントハンドラ設定 *)
    window#connect#destroy ~callback:Main.quit;
    mogura1#connect#clicked
      ~callback:(fun _ ->
		   set_disable mogura1;
		   set_enable mogura2;
		   count := !count + 1;
		   text#set_text ("COUNT: "^string_of_int !count));
    mogura2#connect#clicked
      ~callback:(fun _ ->
		   set_disable mogura2;
		   set_enable mogura1;
		   count := !count + 1;
		   text#set_text ("COUNT: "^string_of_int !count));

    (* 開始 *)
    window#show ();
    Main.main ();;
let _ = Printexc.print main ()

マルチスレッドですらない…。

OMakefile

LablGTK を使うときには gtkInit.cmo をリンクしないといけません。普通に FILES[] とかに書いちゃうと、 omake さんは gtkInit.ml から gtkInit.cmo を作ろうと頑張ってしまうので、OCAML_BYTE_LINK_FLAGS に書きます。
# これで正しいのかはわからないのですが、とりあえず動いてます

USE_OCAMLFIND = true
OCAMLPACKS[] = unix threads lablgtk2
OCAMLINCLUDES += lablgkt2

NATIVE_ENABLED = $(not $(OCAMLOPT_EXISTS))
BYTE_ENABLED = $(OCAMLC_EXISTS)

OCAMLCFLAGS   += -thread -w -s -warn-error a
OCAML_BYTE_LINK_FLAGS += gtkInit.cmo

FILES[] = sampleapp
PROGRAM = sampleapp
OCAML_OTHER_LIBS += unix threads lablgtk

.DEFAULT: $(OCamlProgram $(PROGRAM), $(FILES))

Thread とか Event を使わない場合、 unix とか threads とかはいらないと思われ。

その他適当に

  • コールバック関数はメインスレッドから呼ばれるので GUI の操作を安心して行えます
  • vbox, hbox に add すると、垂直・水平に GUI オブジェクトを並べられる
  • プログレスバーは GRange.progress_bar
  • テキストボックスへのキー入力イベントの取り方
textbox#event#connect#key_release
   ~callback:(fun ev -> let key = GdkEvent.Key.string ev in ...);

感想