gtk2hsを使ってみる
Haskellで、gtkを(久しぶりに)使ってみました。 とりあえず、昔書いたコードが動くところまで行ったので、手順と注意点を記録に残しておきます。
gtkとgtk3というパッケージがあるのですが、gtk3は上手く行かなかったので、そこらへんの記録も。
開発環境
手順
gtkパッケージの場合
- Haskell Platformをインストール
- ここからGTK+ 2.xの
all-in-one bundle
をダウンロード - 中身をパスにスペースを含まないディレクトリに解凍
- 例:
C:\gtk\
- 例:
- その中の
bin
にパスを通す- 例:
C:\gtk\bin
- 例:
- 以下のコマンドを実行
cabal update
cabal install gtk2hs-buildtools
cabal install gtk
module Main where
import Graphics.UI.Gtk
import Control.Monad.Trans ( liftIO )
main = do
initGUI
xml <- builderNew
builderAddFromFile xml "hellogtk2hs.glade"
window <- builderGetObject xml castToWindow "window1"
window `on` unrealize $ mainQuit
closeButton <- builderGetObject xml castToButton "button2"
closeButton `on` buttonPressEvent $ tryEvent $ do
liftIO $ widgetDestroy window
label <- builderGetObject xml castToLabel "label1"
entry <- builderGetObject xml castToEntry "entry1"
applyButton <- builderGetObject xml castToButton "button1"
applyButton `on` buttonPressEvent $ tryEvent $ do
name <- liftIO $ get entry entryText
liftIO $ set label [ labelText := "Hello " ++ name ]
widgetShowAll window
mainGUI
gtk3パッケージの場合
- Haskell Platformをインストール
- ここからGTK+ 3.xの
all-in-one bundle
をダウンロード - 中身をパスにスペースを含まないディレクトリに解凍
- 例:
C:\gtk3\
- 例:
- その中の
bin
にパスを通す- 例:
C:\gtk3\bin
- 例:
- 以下のコマンドを実行
cabal update
cabal install gtk2hs-buildtools
cabal install gtk3
- glade3.14をここからインストール
- 3.8はgtk2用なので注意
- 以下同様
注意点
<イベント>と<イベントモナド>
onClickedとかを使う以下の書き方はもう古いようです:
module Main where
import Graphics.UI.Gtk
import Graphics.UI.Gtk.Glade
main = do
initGUI
Just xml <- xmlNew "hellogtk2hs.glade"
window <- xmlGetWidget xml castToWindow "window1"
onDestroy window mainQuit
closeButton <- xmlGetWidget xml castToButton "button2"
onClicked closeButton $ do
widgetDestroy window
label <- xmlGetWidget xml castToLabel "label1"
entry <- xmlGetWidget xml castToEntry "entry1"
applyButton <- xmlGetWidget xml castToButton "button1"
onClicked applyButton $ do
name <- get entry entryText
set label [ labelText := "Hello " ++ name ]
widgetShowAll window
mainGUI
今どきの書き方は最初のコードを参考にしてください。 新しい書き方の方が、多少書くのが面倒くさくなってくれている分、より厳しい型によるチェックをしてくれます。
基本的な書き方は、
<オブジェクト> `on` <イベント> $ tryEvent $ do <イベントモナド>
と言った感じです。
主要な<イベント>はここのEventsの節にまとめられています。
<イベントモナド>はパラメタライズされており、各種イベントに対応するイベントモナドを設けることで、 チェックを厳格にしているようです。
例えば、<イベント>buttonPressEvent :: WidgetClass self => Signal self (EventM EButton Bool)
に対応する<イベントモナド>はEventM EButton
です。
このモナドの専用の関数としてeventButton :: EventM EButton MouseButton
などがあり、型によって、このコンテキストで使える関数を限定しています。
hoogleでEventM EButton a +gtk
などと検索すると、そのモナドで使える関数の一覧が出てくるので、 その点でも非常に便利です。
ちなみに、<イベントモナド> EventM t
はMonadIOのインスタンスなので、liftIO
を使えば、任意のIOアクションが行えまます(行わざる負えない場合がほとんどです)。
gladeを別にインストールする必要がない件
現在はgtkにgladeがデフォルトで入っているので、gladeパッケージを入れる必要がありません。
gladeパッケージを使うときと使わない時の変更点はだいたいこんな感じです:
gladeパッケージを使うとき(以前の書き方)
import Graphics.UI.Gtk
import Graphics.UI.Gtk.Glade
main = do
initGUI
Just xml <- xmlNew "hellogtk2hs.glade"
window <- xmlGetWidget xml castToWindow "window1"
gladeパッケージ使わないとき(今どきの書き方)
import Graphics.UI.Gtk
main = do
initGUI
xml <- builderNew
builderAddFromFile xml "hellogtk2hs.glade"
window <- builderGetObject xml castToWindow "window1"
gtk3
gtk3は試してみましたが、 どうやらexpose-event(gtk2hsではexposeEvent)がdeplicatedのようで、代用としてdraw eventというのがあるようです。
gtk3パッケージでexposeEvent :: WidgetClass self => Signal self (EventM EExpose Bool)
を使うと実行時エラーがでるので、注意です。
今のところ、私は、
-
gtk2hsにおいてdraw eventに対応する関数を見つけることができない
-
hoogleのAPI searchにgtk3パッケージが対応していない
などの理由でgtkパッケージの方(つまりgtk2へのバインディング)を使っています。
glade
gladeも、
- gtk2 -> glade3.8
- gtk3 -> glade 3.14
と使い分けなければ、上手く行きませんでした。
gtk2ではVBoxとかHBoxとWidgetが分かれていましたが、gtk3ではBoxの属性として、VとHがあるようで(?)、gtk3でglade3.8で作ったVBoxとかHBoxを読み込むとエラーがでました。
おわりに
今後、diagramsパッケージを使用してgtkアプリケーションのDrawingArea上にお絵かきをすることに挑戦する予定なので、 次回の記事はそのレポートの予定です。