根据 threepenny-gui 中的列表框选择更改其他元素
Changes in other elements based on listbox selections in threepenny-gui
所以我有一个简单的示例布局,其中包含一个列表框、一个按钮和一个文本区域,其中单击按钮会更改文本区域中的文本:
import Control.Applicative
import Control.Monad
import Data.Maybe
import qualified Graphics.UI.Threepenny as UI
import Graphics.UI.Threepenny.Core
main :: IO ()
main = startGUI defaultConfig setup
setup :: Window -> UI ()
setup w = do
return w # set UI.title "Simple example"
listBox <- UI.listBox (pure ["First", "Second"]) (pure Nothing) ((UI.string .) <$> (pure id))
button <- UI.button # set UI.text "Button"
display <- UI.textarea # set UI.text "Initial value"
element listBox # set (attr "size") "10"
getBody w #+ [element listBox, element button, element display]
on UI.click button $ const $ do
element display # set UI.text "new text"
我想做的是根据列表框选择进行更改(例如,根据选择将 "new text"
设为 "First"
或 "Second"
)。
我可以很容易地通过组合 userSelection
和 facts
来获得选择,如
facts . userSelection :: ListBox a -> Behavior (Maybe a)
但是因为设置文本区域的值是用
完成的
set text :: String -> UI Element -> UI Element
我不知道如何解决所选内容是 Behavior
。
所有这些对我来说似乎有点单调,我想知道什么是正确的方法。也许我应该在列表框选择完成或更改时做一些事情,而不仅仅是在按下按钮时。
注意:我对 ThreePenny 不熟悉,我只是在阅读文档。
我认为你需要sink
你的列表框到你的文本区域:
element display # sink UI.text ((maybe "new text" id) <$> (facts $ userSelection listBox))
尝试为列表框创建步进器,然后下沉显示
listB <- stepper Nothing (userSelection listBox)
element display # sink UI.text ((maybe "new text" id) <$> (listB)
然后,如果您想使用按钮对行为进行采样
listB <- stepper Nothing (userSelection listBox)
button <- UI.button # set UI.text "Button"
cutedListB <- stepper Nothing (listB <@ UI.click button)
element display # sink UI.text ((maybe "new text" id) <$> (listB)
首先,a regression影响了这里的代码。这个问题现在已经解决了。 Threepenny 0.6.0.3 有一个临时修复,最终修复将包含在之后的版本中。
pastebin you provided 中的代码几乎是正确的。唯一需要的更改是您不需要在按钮单击回调中使用 sink
- 在您的情况下,sink
应该在行为和文本区域的内容之间建立永久连接,响应按钮点击事件而改变的行为值。
为了完整起见,这里有一个完整的解决方案:
{-# LANGUAGE RecursiveDo #-}
module Main where
import Control.Applicative
import Control.Monad
import Data.Maybe
import qualified Graphics.UI.Threepenny as UI
import Graphics.UI.Threepenny.Core
main :: IO ()
main = startGUI defaultConfig setup
setup :: Window -> UI ()
setup w = void $ mdo
return w # set UI.title "Simple example"
listBox <- UI.listBox
(pure ["First", "Second"]) bSelected (pure $ UI.string)
button <- UI.button # set UI.text "Button"
display <- UI.textarea
element listBox # set (attr "size") "10"
getBody w #+ [element listBox, element button, element display]
bSelected <- stepper Nothing $ rumors (UI.userSelection listBox)
let eClick = UI.click button
eValue = fromMaybe "No selection" <$> bSelected <@ eClick
bValue <- stepper "Initial value" eValue
element display # sink UI.text bValue
要带走的两个关键点是:
listBox
的 Behavior (Maybe a)
参数不仅设置了初始选择值,而且还决定了该值在整个应用程序生命周期中的演变。在这个例子中,facts $ UI.userSelection listBox
就是 bSelected
,可以通过 the source code of the Widgets
module. 来验证
- 对事件发生的行为进行采样的典型方法是通过
(<@)
(如果事件携带您希望使用的数据,则为 <@>
)。
所以我有一个简单的示例布局,其中包含一个列表框、一个按钮和一个文本区域,其中单击按钮会更改文本区域中的文本:
import Control.Applicative
import Control.Monad
import Data.Maybe
import qualified Graphics.UI.Threepenny as UI
import Graphics.UI.Threepenny.Core
main :: IO ()
main = startGUI defaultConfig setup
setup :: Window -> UI ()
setup w = do
return w # set UI.title "Simple example"
listBox <- UI.listBox (pure ["First", "Second"]) (pure Nothing) ((UI.string .) <$> (pure id))
button <- UI.button # set UI.text "Button"
display <- UI.textarea # set UI.text "Initial value"
element listBox # set (attr "size") "10"
getBody w #+ [element listBox, element button, element display]
on UI.click button $ const $ do
element display # set UI.text "new text"
我想做的是根据列表框选择进行更改(例如,根据选择将 "new text"
设为 "First"
或 "Second"
)。
我可以很容易地通过组合 userSelection
和 facts
来获得选择,如
facts . userSelection :: ListBox a -> Behavior (Maybe a)
但是因为设置文本区域的值是用
完成的set text :: String -> UI Element -> UI Element
我不知道如何解决所选内容是 Behavior
。
所有这些对我来说似乎有点单调,我想知道什么是正确的方法。也许我应该在列表框选择完成或更改时做一些事情,而不仅仅是在按下按钮时。
注意:我对 ThreePenny 不熟悉,我只是在阅读文档。
我认为你需要sink
你的列表框到你的文本区域:
element display # sink UI.text ((maybe "new text" id) <$> (facts $ userSelection listBox))
尝试为列表框创建步进器,然后下沉显示
listB <- stepper Nothing (userSelection listBox)
element display # sink UI.text ((maybe "new text" id) <$> (listB)
然后,如果您想使用按钮对行为进行采样
listB <- stepper Nothing (userSelection listBox)
button <- UI.button # set UI.text "Button"
cutedListB <- stepper Nothing (listB <@ UI.click button)
element display # sink UI.text ((maybe "new text" id) <$> (listB)
首先,a regression影响了这里的代码。这个问题现在已经解决了。 Threepenny 0.6.0.3 有一个临时修复,最终修复将包含在之后的版本中。
pastebin you provided 中的代码几乎是正确的。唯一需要的更改是您不需要在按钮单击回调中使用 sink
- 在您的情况下,sink
应该在行为和文本区域的内容之间建立永久连接,响应按钮点击事件而改变的行为值。
为了完整起见,这里有一个完整的解决方案:
{-# LANGUAGE RecursiveDo #-}
module Main where
import Control.Applicative
import Control.Monad
import Data.Maybe
import qualified Graphics.UI.Threepenny as UI
import Graphics.UI.Threepenny.Core
main :: IO ()
main = startGUI defaultConfig setup
setup :: Window -> UI ()
setup w = void $ mdo
return w # set UI.title "Simple example"
listBox <- UI.listBox
(pure ["First", "Second"]) bSelected (pure $ UI.string)
button <- UI.button # set UI.text "Button"
display <- UI.textarea
element listBox # set (attr "size") "10"
getBody w #+ [element listBox, element button, element display]
bSelected <- stepper Nothing $ rumors (UI.userSelection listBox)
let eClick = UI.click button
eValue = fromMaybe "No selection" <$> bSelected <@ eClick
bValue <- stepper "Initial value" eValue
element display # sink UI.text bValue
要带走的两个关键点是:
listBox
的Behavior (Maybe a)
参数不仅设置了初始选择值,而且还决定了该值在整个应用程序生命周期中的演变。在这个例子中,facts $ UI.userSelection listBox
就是bSelected
,可以通过 the source code of theWidgets
module. 来验证
- 对事件发生的行为进行采样的典型方法是通过
(<@)
(如果事件携带您希望使用的数据,则为<@>
)。