使用 Reflex.GI.Gtk,如何在事件中使用和强制评估动态

问题描述

使用reflex-gi-gtk-0.2.0.0时 我可以从事件中访问动态:

submitButtonE4 <- eventOnSignal submitButton #clicked 
          (
            do
             let processDyn dynCompany = do
                   case dynCompany of 
                     Just company -> do 
                       path <- chartAnnualROA company fileOptions800x600 --generateChart company
                       Gtk.imageClear chartimage
                       Gtk.set chartimage  [#file := T.pack defaultReportPath]
                       --return x -- path 
                       case T.null $ T.pack path of
                         True ->   return "" --dynCompany
                     nothing -> return "" --  dynCompany 
             return $ ffor  maybeCompanyDyn processDyn
            >>= )

但是为了被评估,我需要将它绑定到一个标签sink submitClickStatusLabel [#label :== ffor submitButtonE4 (T.pack . show)] 它不像在 Dynamic (SpiderTimeline x) (IO (Maybe Company)) 中那样工作。

所以我必须去获取动态绑定到的信息:

          (
            do
              name <- Gtk.get companyCBoxBoxEntryWidget #text
              case Map.lookup name companyMap of 
                Just company -> do 
                  path <- chartAnnualROA company fileOptions800x600 --generateChart company
                  Gtk.imageClear chartimage
                  Gtk.set chartimage  [#file := T.pack defaultReportPath]
                  return path 
                nothing -> return "../investingRIO/src/Data/Reports/initialChart.svg"
            >>= )

现在我可以将它击沉并引起评估。

sink submitClickStatusLabel [#label :== ffor submitButtonE (T.pack . show)]

在使用第一种方法时,我找不到任何强制评估的方法。如何在不下沉到另一个小部件的情况下强制评估?

谢谢

解决方法

我认为您的大部分麻烦来自于您想要在 eventOnSignal 内进行大量工作的事实。这个地方不是为了执行您的业务逻辑的实际繁重工作,也没有为您提供适当的上下文来有效地处理反应性值,例如您目前遇到的 Dynamic。>

eventOnSignal* 系列函数的实际用例是获取反应式网络的基本输入。按钮提供的输入不携带任何实际信息。它只提供何时按钮被点击的信息。对于这种情况,您通常不想直接使用 eventOnSignal,而是使用 eventOnSignal0,所以让我们这样做:

submitClickedE <- eventOnSignal0 submitButton #clicked

由此返回的类型是submitClickedE :: Event t ()。如您所见,Event 有一个 () 作为其值,这正是我们想要的,因为仅单击按钮本身不会产生任何值。但是您想对 IO 中的值调用 processDyn 生成函数,所以让我们首先构造您要执行的 IO 操作:

let processDynD = processDyn <$> dynCompany

此处的赋值类型为 processDynD :: Dynamic t (IO (Maybe Company))。如您所见,IO 尚未执行。幸运的是,reflex 提供了一个操作来在响应值中执行 IO 操作,称为 performEvent :: Event t (Performable m a) -> m (Event t a)。这种类型有两件事不太适合我们目前的需要。首先,它期望 monad 被执行为 Performable m,而我们有 IO,但我们稍后会谈到这一点。第二个也是更紧迫的问题是 performEvent 期望的是 Event,而不是 Dynamic。这是有道理的,因为您不能连续执行 IO 操作。您必须决定何时执行 IO 操作。

您希望在单击 submitButton 时执行 IO 的 AIUI。所以我们想要一个在 Event 触发时触发的 submitClickedE,但它应该触发 processDynD 中的当前值。做这样的事情被称为“用BehaviorEvent进行采样”并且可以使用运算符(<@)来完成。在您的情况下,您想对 Dynamic 进行采样,但您始终可以使用 DynamicBehavior 变成 current。因此,要获得预期的 Event,您可以使用:

let processDynE = current processDynD <@ submitClickedE

分配的值为 processDynE :: Event t (IO (Maybe Company))。但是正如您所看到的,IO 仍然没有被执行。我们现在可以使用前面讨论过的 performEvent 来做到这一点:

processedCompany <- performEvent $ runGtk <$> processDynE

我们使用 runGtkIO 中的 processDynE 提升到所需的 Performable m。返回值的类型为 processedCompany :: Event t (Maybe Company)。您现在可以将其放入您的输出标签中,这是您的初衷:

sink submitClickStatusLabel [#label :== T.pack . show <$> processedCompany]

但请注意,与您最初的尝试不同,我们现在以 Event 而不是 Dynamic 结束。如果您确实需要所有这些中的 Dynamic,则必须使用 EventholdDyn initialValue processedCompany 构造它。但是,您必须提供一个 initialValue,否则在第一次点击 Dynamic 之前 submitButton 没有任何值。

,

这是新版本,基于 Kritzefitz 的回答。

从组合框中选择公司的事件,与之前相同

companySelectionE <- eventOnAttribute companyCboxBoxEntryWidget #text

用行为代替动态。

companySelectionB <- hold Nothing $ ffor companySelectionE (`Map.lookup` companyMap) 

generateChart(从 processDyn 重命名)返回一个 () 而不是 FilePath,这是一种强制求值的尝试,现在由 performEvent 完成。

    let 
      generateChart company = do
        case company of 
          Just companyJ -> do 
            chartAnnualROA companyJ fileOptions800x600 
            Gtk.imageClear chartImage
            Gtk.set chartImage  [#file := T.pack defaultReportPath]
            return () 
          Nothing -> return () 

submitClickedE 现在使用 eventOnSignal0 而不是 eventOnSignal

    submitClickedE <- eventOnSignal0 submitButton #clicked

从所选公司创建图表现在是一种行为而不是动态。

    let generateChartB = generateChart <$> companySelectionB

现在我使用

     let generateChartE = generateChartB <@ submitClickedE 

使用 performEvent,它消除了我正在创建和下沉的所有标签,以试图让我的 IO 进行评估。它还消除了从 generateChart 返回的 FilePath,以及强制求值的尝试。

    processedCompany <- performEvent $ runGtk <$> generateChartE

谢谢帮我清理了很多东西,谢谢。 为了更容易阅读,这里是单引号:

    companySelectionE <- eventOnAttribute companyCbox #text
    companySelectionB <- hold Nothing $ ffor companySelectionE (`Map.lookup` companyMap)
    let 
        generateChart company = do
          case company of 
            Just companyJ -> do 
              chartAnnualROA companyJ fileOptions800x600 
              Gtk.set chartImage  [#file := T.pack defaultReportPath]
              return () 
            Nothing -> return () 
         
    submitClickedE <- eventOnSignal0 submitButton #clicked
    let generateChartB = generateChart <$> companySelectionB
    let generateChartE = generateChartB <@ submitClickedE
    processedCompany <- performEvent $ runGtk <$> generateChartE

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...