gtk2hs を Glade と組み合わせて使うときのメモ。
Haskell の GUI プログラミングを試したくて、テキストボックスに文字列を入れて Enter を押したらラベルに表示されるような簡単なプログラム echo を、gtk2hs を使って書く実験をしてみた。
で、まず Glade というツールで GUI を定義する XMLを生成して、これを適当に書いた Haskell プログラムに読ませたら、こんなエラーが出た
$ ./echo (echo:4887): libglade-WARNING **: Expected <glade-interface>. Got <interface>. (echo:4887): libglade-WARNING **: did not finish in PARSER_FINISH state echo: user error (Pattern match failure in do expression at echo.hs:8:5-12)
なんか Glade が生成した GUI定義XML の形式に問題があるっぽい。
調べてみると、Glade の出力形式には libglade と GtkBuilder の二通りの方法があり、gtk2hs が対応しているのは前者という事らしいのだが、ファイルを保存するときに libglade を選んでも、事態は全然変わらない。
さらに調べてみると Glade の3.8系 と 3.10系 で大きな違いがあって、出力XML に関してだと 3.10系では libglade 形式が無くなってるらしい。自分は、特に意識しないまま 3.10 を使っていた模様。
この2つのバージョン間で、保存時のダイアログに以下のような違いがある。
XML出力の違いは以下のような感じ<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.24"/>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<child>
…
<?xml version="1.0" encoding="UTF-8"?>
<glade-interface>
<widget class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<child>
…
というわけで、Glade の 3.8 系を使えば、gtk2hs がちゃんと処理できる形式の XML になる。
ただし、うちの環境で使ってる Fedora16 なんかでは、「ソフトウェアの追加/削除」から普通に Glade をインストールすると 3.10系が入って来てしまう。従って、この場合 3.8系を別途インストールする必要がある。
これは、ここから glade3-3.8.1.tar.xz を落としてきて、tar Jxf glade3-3.8.1.tar.xz -> ./configure -> make -> make install のようにすれば、/usr/local/bin/glade-3 が使えるようになる。
ちなみに、以下が実験で使った Haskellコード
module Main where
import Graphics.UI.Gtk
import Graphics.UI.Gtk.Glade
import Graphics.UI.Gtk.Gdk.Events as Evt
main = do
initGUI
Just xml <- xmlNew "echo.glade"
window <- xmlGetWidget xml castToWindow "window1"
onDestroy window mainQuit
label <- xmlGetWidget xml castToLabel "label1"
entry <- xmlGetWidget xml castToEntry "entry1"
onKeyPress window $ \(Evt.Key _ eventSent _ _ _ _ _ _ name _) -> do
keyPressHandler label entry name
return eventSent
widgetShowAll window
mainGUI
keyPressHandler :: Label -> Entry -> String -> IO ()
keyPressHandler label entry "Return" = do
name <- get entry entryText
set label [labelText := name]
keyPressHandler _ _ _ = return ()
たかだかこれだけのコードを書くのに、かなり骨を折るが、いちおう動作する。



0 件のコメント:
コメントを投稿