Estoy tratando de hacer una aplicación de juguete, solo para entender cómo escribir programas impulsados por eventos en Haskell. Lo que trato de hacer es dibujar una línea en un lienzo que se mueve hacia adelante cada vez que se presiona una tecla (por lo que es una especie de cursor primordial en un editor de texto).Cómo pasar el estado entre los manejadores de eventos en gtk2hs
Mi problema es que no puedo determinar cuál es la mejor manera de contar la cantidad de veces que el usuario ha presionado una tecla. Obviamente no puedo usar una variable global como lo haría en un programa imperativo, así que presumiblemente necesito pasar el estado en la pila de llamadas, pero en la ejecución de GTK desciende al ciclo principal después de que devuelva cada controlador de eventos y ya que no lo hago controlar el ciclo principal No veo cómo puedo pasar el estado global modificado desde un manejador de eventos. Entonces, ¿cómo puede un manejador de eventos pasar el estado a otro manejador de eventos?
Tengo una especie de solución parcial aquí, donde el evento del teclado re-curry myDraw y lo establece como un nuevo controlador de eventos. No estoy seguro de si esta solución se puede extender, o incluso si es una buena idea.
¿Cuál es la mejor solución de partículas para este problema?
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