2013-01-02 3 views
1

나는 Haskell에서 경험이 없으며 Gtk2Hs를 사용하기 시작했습니다. 그래서 이것은 바보 같은 질문 일 수 있습니다.Gtk2Hs에서 DrawingArea를 사용하는 애니메이션

나는 정의 된 다음 Line 유형이 있습니다

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

을 그리고 나는 DrawingAreaLine의 목록을 그리는 기능을 가지고있다. 문제는이 함수가 동시에 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이 노출 될 때 함수가 호출됩니다 : 나는 Line의 아직 그려 질 필요가있는 추적하기 위해 StateT를 사용하여 고려하지만 한

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 

나는 방법을 모른다 애니메이션을 구현하십시오. 상태를 변경 한 후에 매번 widgetShowAll로 전화를 걸더라도 mainGUI이 호출 될 때까지 창이 표시되지 않습니다.

drawCanvas이 어떻게 든 도면을 처리하는 동안 상태를 지속적으로 업데이트하는 새 스레드를 만들 수 있습니까? 그렇다면 누군가 제게 그러한 행동의 예를 보여줄 수 있습니까? 아니면 아마 더 나은 접근 방법이 있을까요?

답변

3

Gtk2Hs는 정기적으로 함수를 호출하는 "타이머"를 설정할 수 있습니다. 따라서 다음을 수행 할 것입니다 :

  • 대부분의 Gtk2H는 IO 모나드에서 발생하기 때문에 IORef 또는 MVar를 사용하여 애니메이션의 상태를 저장하고 어디에서나 변경할 수 있습니다.
  • mainGUI 전에 에 대한 호출을 추가하십시오 (예 : timeoutAdd (update can lines) 100). 100 밀리 초마다 실행되는 타이머를 설정하고 DrawingArea 및 애니메이션 상태가 매개 변수 인 IORef/MVar와 함께 새 함수 "update"를 호출하십시오.
  • "업데이트"함수에서 애니메이션 상태를 변경하고 widgetQueueDraw can을 호출하여 그리기 영역이 다시 노출되도록합니다. 그러면 expose 이벤트에 연결되어 있으므로 "drawCanvas"가 자동으로 호출됩니다. "업데이트"는 IO Bool을 반환해야합니다. 거짓을 반환하면 타이머가 중지됩니다.
  • 애니메이션 상태를 업데이트하려면 튜플을 사용합니다. 첫 번째 요소는 그릴 선을 저장하고 두 번째 요소는 다른 선의 목록을 저장합니다.

애니메이션의 상태와 그림을 별도의 기능으로 업데이트하는 것이 좋습니다.