2011-03-14 4 views
9

저는 하스켈에서 이벤트 중심의 프로그램을 작성하는 방법에 대해 머리 글을 쓰려고 장난감 애플리케이션을 만들려고합니다. 내가하려고하는 것은 키를 누를 때마다 앞으로 움직이는 캔버스에 선을 그리는 것입니다. 그래서 텍스트 편집기에서 원시 커서의 일종입니다.gtk2hs의 이벤트 핸들러간에 상태를 전달하는 방법

내 문제는 사용자가 키를 누른 횟수를 계산하는 가장 좋은 방법을 찾지 못하는 것입니다. 당연히 명령형 에서처럼 전역 변수를 사용할 수 없으므로 호출 스택에서 상태를 전달해야하지만 GTK 실행에서는 각 이벤트 핸들러가 반환 된 후 주 루프로 내려갑니다. 메인 루프 제어 하나의 이벤트 핸들러에서 변경된 글로벌 상태를 어떻게 전달할 수 있는지 알지 못한다. 그렇다면 한 이벤트 핸들러가 어떻게 다른 이벤트 핸들러에 상태를 전달할 수 있습니까?

여기에는 키보드 이벤트가 myDraw를 다시 카레하며 이벤트 처리기를 새 것으로 설정하는 일종의 부분적인 해결 방법이 있습니다. 이 솔루션을 확장 할 수 있는지, 아니면 좋은 생각인지 확실하지 않습니다.

이 문제의 가장 좋은 입자 솔루션은 무엇입니까?

import Graphics.UI.Gtk 
import Graphics.Rendering.Cairo 

main :: IO() 
main= do 
    initGUI 
    window <- windowNew 
    set window [windowTitle := "Hello World", 
       windowDefaultWidth := 300, windowDefaultHeight := 200] 

    canvas <- drawingAreaNew 
    containerAdd window canvas 

    widgetShowAll window 
    draWin <- widgetGetDrawWindow canvas 
    canvas `on` exposeEvent $ do liftIO $ renderWithDrawable draWin (myDraw 10) 
            return False 

    window `on` keyPressEvent $ onKeyboard canvas 
    window `on` destroyEvent $ do liftIO mainQuit 
            return False 

    mainGUI 

onKeyboard :: DrawingArea -> EventM EKey Bool 
onKeyboard canvas = do 
    liftIO $ do drawWin <- widgetGetDrawWindow canvas 
       canvas `on` exposeEvent $ do liftIO $renderWithDrawable drawWin (myDraw 20) 
              return False 
       widgetQueueDraw canvas 
    return False 



myDraw :: Double -> Render() 
myDraw pos = do 
    setSourceRGB 1 1 1 
    paint 
    setSourceRGB 0 0 0 

    moveTo pos 0 
    lineTo pos 20 
    stroke 

답변

7

먼저 글로벌 계정이 있어야합니다. 이 솔루션을 나쁜 형식으로 무시하면 MVar의 작업처럼 보입니다. main에서 당신은 당신이 onKeyboard에 업데이트 할 수있는 새로운 MVAR을하고 myDraw 체크인 : 첫째합니다 (MVar을 제공하기 위해 일부 응용 프로그램을 사용하여 인수로 함수를 전달할 때 변경 가능 상태를 공유하는 것은 종종 유용하다는 것을

... 
import Control.Concurrent.MVar 

main = do 
    ... 
    mv <- newMVar 0 
    .... 
    canvas `on` exposeEvent $ do liftIO $ renderWithDrawable draWin (myDraw mv 10) 
    ... 
    window `on` keyPressEvent $ onKeyboard canvas mv 

onKeyboard canvas mv = do 
    modifyMVar_ mv (\x -> return (x + 1)) 
    .... 

myDraw mv pos = do 
    val <- readMVar mv 
    ... 

주 또는 TVar, IORef, 무엇이든).

오 경고 및 경고 : MVars는 엄격하지 않습니다 - 응용 프로그램이 값을 강제로 지정하지 않고 (즉, 포함 된 값을 읽고 비교하는) 가능성이있는 경우 작성하기 전에 값을 강제로 작성하여 빌드하지 않도록해야합니다 큰 썽크.