试图在threepenny-gui中渲染具有特殊行为的字段

时间:2014-01-01 20:18:53

标签: haskell user-interface threepenny-gui

我想要做的是设置显示焦点时的详细信息的字段,但是当它们不在时会显示摘要。例如。

A)。当它失去焦点(变得模糊?)时,我将值保存在(状态?)Map中,然后将值更改为旧值的函数(即汇总值)

B)。当它获得焦点时 - 我将汇总值替换为我在Map

中保存的旧值

我无法弄清楚如何做到这一点,但我想我可能需要一个状态monad和UI monad。我的尝试是:

renderField :: Map->Int->UI (Element, Map)
renderField vs ix = do
    input <- UI.input  
    on UI.blur input $ \_ -> void $ do
        fieldValue <- get value input
        let newVs = insert ix fieldValue vs
        return input # set UI.value (calcNewValue fieldValue)
    on UI.focus input $ \_ -> void $ do
        let savedValue = findWithDefault "" ix vs
        return input # set UI.value savedValue
    return (input, newVs)

但我无法让这张地图发挥作用 - 因为它需要跟踪所有的电话......我想它应该是State monad还是什么?

感谢。

<磷>氮

1 个答案:

答案 0 :(得分:2)

的确,你需要跟踪状态。

但是,通常的模式s -> (a,s)(状态monad)在这里不适用,因为您正在使用回调函数。对于这些,您需要一个不同的模式。

在传统的命令式样式中,人们会在这里使用一个可变变量,例如IORef。请注意,不再需要跟踪索引 - 您可以将IORef视为大型可变地图中的索引。

renderField :: UI Element
renderField = do
    input <- UI.input
    state <- liftIO $ newIORef

    on UI.blur input $ \_ -> do
        fieldValue <- get value input
        liftIO $ writeIORef state fieldValue    
        element input # set UI.value (calcNewValue fieldValue)

    on UI.focus input $ \_ -> do
        savedValue <- liftIO $ readIORef state
        element input # set UI.value savedValue

    return input

或者,您也可以在Threepenny中使用功能反应式编程(FRP)。请注意,API仍有些初步,以下代码特定于threepenny-gui版本0.4.*

renderField :: UI Element
renderField = do
    input  <- UI.input

    bValueUser <- stepper "" $ UI.valueChange input
    bState     <- stepper "" $ bValueUser <@ UI.blur input
    bValue     <- stepper "" $ fmap head $ unions
        [ (calcNewValue <$> bValueUser) <@ UI.blur input
        , bState <@ UI.focus input
        ]
    element input # sink UI.value bValue 

同样,这段代码中还有一些细微之处和瑕疵,但这是我想要了解的一般方向。有关FRP及其如何应用于GUI开发的一些初步信息可以在{{3 }}

我建议您在需要快速完成任务时使用熟悉的解决方案(IORef),并在有足够的空闲时间时探索FRP解决方案。 documentation主要使用FRP样式。

(披露:我是Threepenny的作者。)