首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Reflex.GI.Gtk,如何在事件中使用和强制动态求值

使用Reflex.GI.Gtk,如何在事件中使用和强制动态求值
EN

Stack Overflow用户
提问于 2021-03-04 23:15:54
回答 2查看 81关注 0票数 3

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

代码语言:javascript
复制
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))中那样工作。

因此,我必须去获取动态绑定到的信息:

代码语言:javascript
复制
          (
            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)]

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

谢谢

EN

回答 2

Stack Overflow用户

发布于 2021-03-05 19:00:03

我认为您的大部分麻烦都来自于这样一个事实,即您想要在eventOnSignal中做大量的工作。这个地方并不打算做实际繁重的业务逻辑工作,它也不会为您提供适当的上下文来有效地使用响应值,例如您当前正在经历的Dynamic

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

代码语言:javascript
复制
submitClickedE <- eventOnSignal0 submitButton #clicked

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

代码语言:javascript
复制
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操作。

AIUI您希望在单击submitButton时执行IO。所以我们想要一个在submitClickedE触发时触发的Event,但它应该在processDynD内部触发当前值。这样做被称为“使用EventBehavior进行采样”,可以使用操作符(<@)来完成。在本例中,您希望对Dynamic进行采样,但您始终可以使用currentDynamic转换为Behavior。因此,要获得预期的Event,您可以使用以下命令:

代码语言:javascript
复制
let processDynE = current processDynD <@ submitClickedE

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

代码语言:javascript
复制
processedCompany <- performEvent $ runGtk <$> processDynE

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

代码语言:javascript
复制
sink submitClickStatusLabel [#label :== T.pack . show <$> processedCompany]

但请注意,与您最初的尝试不同,我们现在使用的是Event而不是Dynamic。如果您实际上需要所有这些内容的Dynamic,则必须使用holdDyn initialValue processedCompanyEvent构造它。但是,您必须提供一个initialValue,否则在第一次单击Dynamic之前,submitButton就没有值了。

票数 2
EN

Stack Overflow用户

发布于 2021-03-05 22:45:13

这是基于Kritzefitz的答案的新版本。

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

代码语言:javascript
复制
companySelectionE <- eventOnAttribute companyCboxBoxEntryWidget #text

将动态替换为行为。

代码语言:javascript
复制
companySelectionB <- hold Nothing $ ffor companySelectionE (`Map.lookup` companyMap) 

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

代码语言:javascript
复制
    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

代码语言:javascript
复制
    submitClickedE <- eventOnSignal0 submitButton #clicked

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

代码语言:javascript
复制
    let generateChartB = generateChart <$> companySelectionB

现在,我使用<@从submit事件创建一个新事件并生成图表行为。

代码语言:javascript
复制
     let generateChartE = generateChartB <@ submitClickedE 

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

代码语言:javascript
复制
    processedCompany <- performEvent $ runGtk <$> generateChartE

谢谢为我理清了很多事情,谢谢。为了更容易阅读,这里用了一个引号:

代码语言:javascript
复制
    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
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66477914

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档