【问题标题】:How to pass state between event handlers in gtk2hs如何在 gtk2hs 中的事件处理程序之间传递状态
【发布时间】:2011-03-14 01:39:15
【问题描述】:

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

我的问题是我无法计算出计算用户按键次数的最佳方法。显然我不能像在命令式程序中那样使用全局变量,所以大概我需要在调用堆栈上传递状态,但是在 GTK 中,在每个事件处理程序返回后执行下降到主循环,因为我没有控制主循环我看不到如何从一个事件处理程序传递更改的全局状态。那么一个事件处理程序如何将状态传递给另一个事件处理程序呢?

我在这里有一种部分解决方案,其中键盘事件 re-curries 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 

【问题讨论】:

    标签: haskell gtk2hs


    【解决方案1】:

    首先,你可以有一个全局的。忽略该解决方案是错误的形式,这看起来像是MVar 的工作。在 main 中,您只需创建一个新的 MVar,您可以在 onKeyboard 中更新它并签入 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
        ...
    

    请注意,通过首先使用部分应用程序提供MVar(或TVarIORef,等等)将函数作为参数传递时,共享可变状态通常也很有用。

    哦,还有一个警告:MVar 并不严格 - 如果应用程序有可能在不强制值的情况下写入很多(即读取和比较包含的 Int),那么您应该在写入之前强制值以避免建立一个巨大的thunk。

    【讨论】:

      猜你喜欢
      • 2023-03-23
      • 1970-01-01
      • 1970-01-01
      • 2018-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多