Я пытаюсь сделать игрушечное приложение, просто чтобы понять, как писать программы, управляемые событиями в 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