With 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)]

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

感谢

以下是根据Kritzefitz的回答编写的新版本。

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

相同
companySelectionE <- eventOnAttribute companyCboxBoxEntryWidget #text

将动态替换为行为

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

generateChart(从processDyn重命名)返回()而不是FilePath,这是试图强制求值,现在由performanvent完成。

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 

和performanvent的使用,它消除了我创建和下沉到的所有标签,试图让我的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

我认为你的大部分麻烦来自于这样一个事实,你想在eventOnSignal中做大量的工作。这个地方并不打算做实际的业务逻辑的繁重工作,也没有为您提供适当的上下文来有效地处理响应性值,如您目前正在经历的Dynamics。

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

submitClickedE <- eventOnSignal0 submitButton #clicked

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

let processDynD = processDyn <$> dynCompany

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

当单击submitButton时,您希望执行IO。因此,我们希望EventsubmitClickedE触发时触发,但它应该触发processDynD中的当前值。做这样的事情被称为"用Event采样Behavior",可以使用运算符(<@)来完成。在您的情况下,您想要采样Dynamic,但您始终可以使用currentDynamic转换为Behavior。因此,要获得预期的Event,可以使用以下命令:

let processDynE = current processDynD <@ submitClickedE

赋值值为processDynE :: Event t (IO (Maybe Company))。但是正如你所看到的,IO仍然没有被执行。我们现在可以像前面讨论的那样使用performEvent来完成:

processedCompany <- performEvent $ runGtk <$> processDynE

我们使用runGtkprocessDynE中的IO提升到所需的Performable m。返回值类型为processedCompany :: Event t (Maybe Company)。现在,您可以将其放入输出标签中,就像您最初的意图一样:

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

请注意,与您最初的尝试不同,我们现在最终使用Event而不是Dynamic。如果您确实需要从所有这些中获得Dynamic,则必须使用holdDyn initialValue processedCompanyEvent构建它。但是你必须提供一个initialValue,否则在submitButton第一次被点击之前,Dynamic就没有值了。

相关内容

  • 没有找到相关文章

最新更新