Haskell 如何在gtk2hs中的事件处理程序之间传递状态

Haskell 如何在gtk2hs中的事件处理程序之间传递状态,haskell,gtk2hs,Haskell,Gtk2hs,我正在尝试制作一个玩具应用程序,只是想了解如何用Haskell编写事件驱动程序。我想做的是在画布上画一条线,每当按下一个键时,画布就会向前移动(所以它就像是文本编辑器中的原始光标) 我的问题是我无法计算出计算用户按键次数的最佳方法。显然,我不能像在命令式程序中那样使用全局变量,因此我可能需要在调用堆栈上传递状态,但在GTK中,在每个事件处理程序返回后,执行下降到主循环中,因为我不控制主循环,所以我不知道如何从一个事件处理程序传递更改的全局状态。那么,一个事件处理程序如何将状态传递给另一个事件处理

我正在尝试制作一个玩具应用程序,只是想了解如何用Haskell编写事件驱动程序。我想做的是在画布上画一条线,每当按下一个键时,画布就会向前移动(所以它就像是文本编辑器中的原始光标)

我的问题是我无法计算出计算用户按键次数的最佳方法。显然,我不能像在命令式程序中那样使用全局变量,因此我可能需要在调用堆栈上传递状态,但在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 
import Graphics.UI.Gtk
导入Graphics.Rendering.Cairo
main::IO()
main=do
initGUI

窗口首先,您可以有一个全局窗口。将该解决方案视为糟糕的形式而忽略,这看起来像是一项针对某个客户的工作。在
main
中,您只需创建一个新的MVar,您可以在键盘上的
中更新它,然后签入
myDraw

...
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
    ...
。。。
导入控制.Concurrent.MVar
main=do
...
中压回路(x+1))
....
myDraw mv pos=do
瓦尔