我有一个使用 Gtk2Hs 绑定的小 Haskell 程序。可以通过单击 DrawingArea 在程序窗口上绘制点(小方块):
[...]
image <- builderGetObject gui castToDrawingArea "drawingarea"
p <- widgetGetDrawWindow image
gc <- gcNewWithValues p (newGCValues { foreground = Color 0 0 0,
function = Copy })
on image buttonPressEvent (point p gc)
set image [ widgetCanFocus := True ]
[...]
point :: DrawWindow -> GC -> EventM EButton Bool
point p gc = tryEvent $ do
(x', y') <- eventCoordinates
liftIO $ do
let x = round x'
let y = round y'
let relx = x `div` 4
let rely = y `div` 4
gcval <- gcGetValues gc
gcSetValues gc (newGCValues { function = Invert })
drawRectangle p gc True (relx * 4) (rely * 4) 4 4
gcSetValues gc gcval
通过试错法并在阅读 Hackage 的文档后,我设法将按钮按下事件添加到绘图区域,因为小部件默认情况下不提供此事件的信号。但是,我不了解 EventM 的定义和用法,所以如果我必须再次向小部件添加新事件,恐怕我将不得不与 EventM monad 斗争。我必须说我仍然不够精通 Haskell。我有点理解简单的 monad 是如何工作的,但是这个“type EventM ta = ReaderT (Ptr t) IO a”(在 Graphics.UI.Gtk.Gdk.EventM 中定义)对我来说似乎是个谜。
我的问题是:有人可以解释一下 EventM monad 的内部结构吗?例如在“buttonPressEvent :: WidgetClass self => Signal self (EventM EButton Bool)”的情况下。