【发布时间】:2016-08-15 12:22:16
【问题描述】:
在下面的代码示例中,我尝试创建一个包含许多选择元素的框,并使用行为将它们的选择组合到一个值列表中。 (代码在 ghci 中编译/运行,只需要threepenny-gui)
{-# LANGUAGE RecursiveDo #-}
module Threepenny.Gui where
import Prelude hiding (lookup)
import Control.Monad
import Data.List
import Data.Traversable
import Data.Maybe
import Data.Monoid
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Graphics.UI.Threepenny as UI
import Graphics.UI.Threepenny.Core hiding (delete)
{-----------------------------------------------------------------------------
(#) Reverse function application: flip $
(#+) Append DOM elements as children to given element: parent #+ children
(#.) Returns UI Element with CSS class changed to second parameter
------------------------------------------------------------------------------}
gui :: IO ()
gui = startGUI defaultConfig setup
fixedTextarea = UI.textarea # set style [("resize", "none"), ("height", "14px"), ("width", "500px")]
combinedBeh :: MonadIO m => [Element] -> m (Behavior ([Maybe Int]))
combinedBeh sl = sequenceA <$> sequence blist
where blist = fmap (stepper Nothing . UI.selectionChange ) sl
selectDivWrong :: UI (Element, Behavior [Maybe Int])
selectDivWrong = do
let select options = UI.select
# set style [("display","inline-block"), ("width", "150px"), ("margin", "0px 0px 4px 0px")]
#+ fmap (\x -> UI.option # set UI.text (show x)) options
selectionList :: [UI Element]
selectionList = replicate 6 $ select [0, 1, 2, 3, 4, 5]
selectionList' <- (sequence selectionList :: UI [Element])
bSelectionList <- combinedBeh selectionList'
mainBox <- UI.mkElement "selectDiv"
# set style [("display","inline-block"), ("background-color", "#333344"),
("height", "200px"), ("width", "150px"), ("padding", "1px")] --
#+ (selectionList) -- unsequenced list of UI elements. The behavior (bSelectionList) should have all the info it needs though(?).
-- why does (#+) not have the same UI info as bSelectionList ?
return (mainBox, bSelectionList)
selectDivCorrect :: UI (Element, Behavior [Maybe Int])
selectDivCorrect = do
let select options = UI.select
# set style [("display","inline-block"), ("width", "150px"), ("margin", "0px 0px 4px 0px")]
#+ fmap (\x -> UI.option # set UI.text (show x)) options
selectionList :: [UI Element]
selectionList = replicate 6 $ select [0, 1, 2, 3, 4, 5]
selectionList' <- (sequence selectionList :: UI [Element])
bSelectionList <- combinedBeh selectionList'
mainBox <- UI.mkElement "selectDiv"
# set style [("display","inline-block"), ("background-color", "#333344"),
("height", "200px"), ("width", "150px"), ("padding", "1px")] --
#+ (fmap pure selectionList')
return (mainBox, bSelectionList)
setup :: Window -> UI ()
setup window = void $ mdo
(sDiv1, bSDiv) <- selectDivWrong
text1 <- fixedTextarea # sink UI.text (show <$> bSDiv)
(sDiv2, bSDiv2) <- selectDivCorrect
text2 <- fixedTextarea # sink UI.text (show <$> bSDiv2)
getBody window
#+ [grid
[ [element sDiv1]
, [element text1]
, [element sDiv2]
, [element text2]
]]
# set style [("background-color", "#eeeeee")]
最初我想使用selectDivWrong,但发现我需要将其修改为selectDivCorrect。我的问题是我不明白为什么存在功能差异。在这两种情况下,selectionList 包含所有需要添加的元素,bSelectionList 结合了所有行为。我不确定UI 如何处理所有状态和事件(而且我还没有大量使用 monads/applicatives),但我怀疑在正确的版本中,组合的UI 上下文被添加到' top level' 并因此传递给(#+)(或UI.mkElement?),但在错误版本的UI Elements 列表中仍未使用。
不过,我仍然不确定我是否遗漏了什么。我真的很想确定并找到有助于在未来识别此类问题的解释,因为我基本上通过反复试验找到了解决方案。 (也可以随意重命名问题...)
【问题讨论】: