2013-01-02 26 views
1

我對Haskell並不是很有經驗,我剛開始使用Gtk2Hs,所以這可能是一個愚蠢的問題。在Gtk2Hs中使用DrawingArea的動畫

我已經定義了以下Line類型:

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

而且我有借鑑了DrawingAreaLine個列表的功能。問題是這個函數同時繪製了所有的Line,但是我想在兩個Line之間稍微延遲一次繪製一個。

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跟蹤其中Line■找尚未得出考慮,但我不知道該怎麼實施動畫。即使每次改變狀態後都會調用widgetShowAll,窗口將不會顯示,直到調用mainGUI

是否有可能創造一個新的線程,不斷更新狀態,而drawCanvas以某種方式照顧繪圖?如果是這樣,請有人給我看一個這樣的行爲的例子嗎?或者有更好的方法嗎?

回答

3

Gtk2Hs允許設置「定時器」,定期調用函數。所以我會做以下事情:

  • 因爲大多數Gtk2H發生在IO monad中,所以使用IORef或MVar來存儲動畫的狀態並將其更改到任何位置。
  • 調用timeoutAdd添加mainGUI之前,像這樣:timeoutAdd (update can lines) 100設置將運行每100毫秒,並調用一個新的功能「更新」與繪圖區和IOREF /無功與動畫狀態參數的計時器。
  • 在功能「更新」改變動畫狀態,並呼籲widgetQueueDraw can使繪圖區域重新暴露出來。這將自動調用「drawCanvas」,因爲它連接到了揭露事件。 「更新」必須返回一個IO Bool。返回False將停止計時器。我想使用一個元組。第一個元素將存儲要繪製的線,第二個元素將存儲其他線的列表。

我覺得它有意義的更新動畫的狀態和繪圖在不同的功能。