对于我的图表工具,我想保持核心模型的代码与 GUI 隔离。
在下面的示例中,“状态”是用 传递的vDiag
,它是一个Tvar
。这是 wx 中的设计决策。现在,对于我的图表工具,我希望将核心模型“存储”在一个fgl
图表中(其中包含复杂类型),并且wx
只给出一个视图;比如说在这个例子中,绘画时读取访问的点列表,以及单击、拖动等时要写入的一些功能......。我首先想到了一些 Monad 堆栈,但即使将 StateT 和来自 wx 的 IO 组合起来看起来也并不简单,因为 io 动作遍布在回调的代码中(点击、绘画等)。感觉就像在堆栈底部有 IO 不再适合了。
那么你如何传递一个状态,或者它不是要走的路?(我直觉这是经典。RFP 是这样开始的吗?)
(在代码中,当点击时绘制红色圆圈,点列表在 a 中传递Tvar
vDiag
。我在等效状态访问器所在的位置标记了“--fgl”。并设置了一个基本的 fgl 测试图访问器说明。我想提出一个状态)(我最初试图在没有 FRP 的情况下试一试 - 反应香蕉,以了解问题,但我想我可能已经成功了 ;-)
module Main where
import Graphics.UI.WX hiding (empty)
import Data.Graph.Inductive
main
= start ballsFrame
ballsFrame
= do
vDiag <- varCreate []
--gDiag <- initg -- fgl
frame <- frame [text := "Demo"]
p <- panel frame []
file <- menuPane [text := "&File"]
quit <- menuQuit file [on command := close frame]
set frame [text:= "testing", menuBar := [file] ]
set p [on click := drawBins vDiag p , on paint := paintDiag vDiag ]
-- fgl pass the var around
return ()
where
drawBins d ppanel pt =
do varUpdate d (pt:)
-- addpoint f g -- fgl : insert a point
repaint ppanel
-- paint the balls
paintDiag vdiag dc view
= do balls <- varGet vdiag -- getPointsFromGraph
-- fgl : change to get the list of points
set dc [brushColor := red, brushKind := BrushSolid]
mapM_ (drawDiag dc) balls
drawDiag dc pt
= circle dc pt 10 []
-- basic fgl test graph accessors I would like to put in a State and replace vDiag
initg:: Gr Point String
initg = mkGraph [(1,pt 10 10),(2,pt 30 30)] [(1,2,"truc"), (2,1,"revtruc")]
getPointsFromGraph :: Graph gr => gr b b1 -> [b]
getPointsFromGraph g = map snd $ labNodes g
-- getPointsFromGraph initg = [Point {pointX = 10, pointY = 10},Point {pointX = 30, pointY = 30}]
addpoint :: DynGraph gr => a -> gr a b -> gr a b
addpoint p g = -- add a point p into graph p
insNode (4,p) g