4

所以我有一个简单的示例布局,其中包含一个列表框、一个按钮和一个 textarea,单击按钮会更改 textarea 中的文本:

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"选择)。

我可以很容易地通过组合userSelectionfacts作为选择

facts . userSelection :: ListBox a -> Behavior (Maybe a)

但是因为设置 textarea 的值是用

set text :: String -> UI Element -> UI Element

我不知道如何解决选择是Behavior.

这一切对我来说似乎有点生疏,我想知道这样做的正确方法是什么。也许我应该在列表框选择完成或更改时已经做一些事情,而不仅仅是在按下按钮时。

4

3 回答 3

4

首先,有一个回归影响了这里的代码。现在这个问题已经解决了。Threepenny 0.6.0.3 有一个临时修复,最终的修复将包含在之后的版本中。


您提供的 pastebin中的代码几乎是正确的。唯一需要的更改是您不需要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

要带走的两个关键是:

  • to的Behavior (Maybe a)参数listBox不仅设置初始选定的值,而且确定该值在整个应用程序生命周期中的演变。在这个例子中,facts $ UI.userSelection listBox只是bSelected,可以通过模块的源代码Widgets来验证。
  • 对事件发生的行为进行采样的典型方法是通过(<@)(或者<@>如果事件携带您希望使用的数据)。
于 2015-06-19T17:31:05.830 回答
1

注意:我对 ThreePenny 不熟悉,我只是在阅读文档。

我认为您需要将sink列表框放入您的文本区域:

element display # sink UI.text ((maybe "new text" id) <$> (facts $ userSelection listBox)) 
于 2015-06-09T16:08:27.023 回答
1

尝试为列表框创建一个步进器,然后下沉显示

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) 
于 2015-06-15T20:21:30.197 回答