DrawingAreaにタイムラインを表示できた
前回(http://hshstter.hatenablog.com/entry/2012/04/12/232132)挑戦して解決しなかったDrawingArea更新の件が解決しました。
わかったことは、
(1)onExposeイベントにセットしたアクションは、drawWindowClearAreaExposeなどで再描画するとちゃんと実行される。
(2)たとえば、変数xに依存するアクションact(x)をonExposeイベントにセットして実行する場合、
act(a)をonExposeにセットして、act(b)を再度onExposeにセットして再描画しても、act(a)の結果が表示される。
→おそらく、2回目以降のonExposeの実行は無視される?(かなり怪しい。それ以外の問題があるのかもしれない)
なので、前回のようなコードではダメで、解決法として、 更新する可能性がある変数をIORefで持っておいて、drawWindowClearAreaExposeでonExposeにセットしたアクションが実行される際に表示するテキストをreadIORefで読み込み直す という実装にするとちゃんと更新されました。
つまりたとえば
str <- makeString
onExpose $ \_ -> do
drawString str
ではなく
onExpose $ \_ -> do
str <- readIORef stringRef
drawString str
とすれば、再描画時にDrawingArea内が変更されます。(変更したい場合は、ここで指定したstringRefの内容をwriteIORefで書き換えればよい)
タイムラインを追加する関数(addTimeline)/タイムラインを更新する関数(updateTimeline)を分け、タイムライン追加関数でonExposeイベントにタイムラインを表示し、更新はupdateTimeline関数でdrawWindowClearAreaExposeアクションを実行することで行うようにしました。
ただ、この実装のままだとちょっと問題があって、2つ以上タイムラインを表示させたい時(List, Mentionなど)に追加できないという問題があります。将来的にはそういう機能は付けたいので、GUIデータ型にある「タイムライン一覧」をIORefにし、onExposeでこの一覧を読み込んですべて表示する、という変更が必要になると思います。(その場合、addTimelineではonExposeイベントへのアクションの設定は行わず、GUIのタイムライン一覧への追加のみ行うようにすればいいですね)
それにしても、副作用ばかりでHaskellっぽくないコードができつつありますね……何とかしたいです。