使用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
中做大量的工作。这个地方并不打算做实际的业务逻辑的繁重工作,也没有为您提供适当的上下文来有效地处理响应性值,如您目前正在经历的Dynamic
s。
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。因此,我们希望Event
在submitClickedE
触发时触发,但它应该触发processDynD
中的当前值。做这样的事情被称为"用Event
采样Behavior
",可以使用运算符(<@)
来完成。在您的情况下,您想要采样Dynamic
,但您始终可以使用current
将Dynamic
转换为Behavior
。因此,要获得预期的Event
,可以使用以下命令:
let processDynE = current processDynD <@ submitClickedE
赋值值为processDynE :: Event t (IO (Maybe Company))
。但是正如你所看到的,IO
仍然没有被执行。我们现在可以像前面讨论的那样使用performEvent
来完成:
processedCompany <- performEvent $ runGtk <$> processDynE
我们使用runGtk
将processDynE
中的IO
提升到所需的Performable m
。返回值类型为processedCompany :: Event t (Maybe Company)
。现在,您可以将其放入输出标签中,就像您最初的意图一样:
sink submitClickStatusLabel [#label :== T.pack . show <$> processedCompany]
请注意,与您最初的尝试不同,我们现在最终使用Event
而不是Dynamic
。如果您确实需要从所有这些中获得Dynamic
,则必须使用holdDyn initialValue processedCompany
从Event
构建它。但是你必须提供一个initialValue
,否则在submitButton
第一次被点击之前,Dynamic
就没有值了。