2

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

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

乙)。当它获得焦点时 - 我将汇总值替换为我保存在地图中的旧值

我不知道该怎么做,但我想我可能需要一个状态单子和 UI 单子。我的尝试是:

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 什么的?

谢谢。

ñ

4

1 回答 1

2

实际上,您需要跟踪状态。

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

在传统的命令式风格中,人们会在这里使用可变变量,例如IORef. 请注意,不再需要跟踪索引——您可以将 anIORef视为大型可变映射中的索引。

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-guiversion 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 开发的一些初步信息可以在文档中找到。

我的建议是IORef当您需要快速完成某事时使用熟悉的解决方案 ( ),并在您有大量空闲时间时探索 FRP 解决方案。示例代码主要使用FRP 样式。

(披露:我是三便士的作者。)

于 2014-01-04T10:14:27.683 回答