【问题标题】:Animation using DrawingArea in Gtk2Hs在 Gtk2Hs 中使用 DrawingArea 的动画
【发布时间】:2013-01-02 05:12:30
【问题描述】:

我在 Haskell 方面的经验并不多,而且我刚刚开始使用 Gtk2Hs,所以这可能是一个愚蠢的问题。

我定义了以下Line 类型:

type Coord = (Int,Int)
type Line = (Coord,Coord)

我有一个函数可以在DrawingArea 上绘制Lines 的列表。问题是这个函数同时绘制所有Lines,但我想一次绘制一个,两个Lines之间有一点延迟。

render :: [Line] -> IO ()
render lines =
  do initGUI
     win <- windowNew
     windowSetTitle win "Animation"
     win `onDestroy` mainQuit

     can <- drawingAreaNew
     can `onSizeRequest` return (Requisition 400 400)
     can `onExpose` drawCanvas lines can

     but <- buttonNewWithLabel "Quit"
     but `onClicked` mainQuit
     hbox <- hBoxNew False 0
     boxPackStart hbox but PackRepel 150

     vbox <- vBoxNew False 5
     containerAdd vbox can
     containerAdd vbox hbox
     containerAdd win vbox

     widgetShowAll win
     mainGUI

DrawingArea 暴露时调用这个函数:

drawCanvas :: [Line] -> DrawingArea -> event -> IO Bool
drawCanvas lines can _evt =
  do dw <- widgetGetDrawWindow can
     drawWindowClear dw
     gc <- gcNew dw
     mapM_ (\(a,b) -> drawLine dw gc a b) lines
     return True

我考虑过使用StateT 来跟踪哪些Lines 尚未绘制,但我不知道如何实现动画。即使每次更改状态后调用widgetShowAll,窗口也不会显示,直到调用mainGUI

是否可以在drawCanvas 以某种方式处理绘图的同时创建一个不断更新状态的新线程?如果是这样,有人可以给我看一个这种行为的例子吗?或者有没有更好的方法?

【问题讨论】:

    标签: haskell gtk2hs


    【解决方案1】:

    Gtk2Hs 允许设置定期调用函数的“定时器”。所以我会做以下事情:

    • 因为大多数 Gtk2H 发生在 IO monad 中,所以使用 IORef 或 MVar 来存储动画的状态并在任何地方进行更改。
    • 在 mainGUI 之前添加对timeoutAdd 的调用,如下所示:timeoutAdd (update can lines) 100 设置一个每 100 毫秒运行一次的计时器,并使用 DrawingArea 和带有动画状态的 IORef/MVar 调用一个新函数“update”作为参数。
    • 在“更新”函数中更改动画状态并调用widgetQueueDraw can,以便重新显示绘图区域。这将自动调用“drawCanvas”,因为它连接到暴露事件。 “更新”必须返回一个 IO Bool。返回 False 将停止计时器。
    • 要更新动画状态,我会使用一个元组。第一个元素将存储要绘制的线,第二个元素将存储其他线的列表。

    我发现在单独的函数中更新动画的状态和绘图很有意义。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多