我目前正在使用reactive-banana和reactive-banana-wx软件包重新设计一个传统的wxHaskell。但是,为了避免动态网络构建(我遇到了MVar上的线程块),我现在通过预构建一组固定的wxHaskell小部件来模仿这一点,我根据需要设置了可见性。可见性由sink
函数设置为Behavior
。但是,wxHaskell要求在通过sink
对所有这些小部件进行适当修改之后,需要随后更改包含这些小部件的面板的布局。这意味着sink
实际上应该是网络的一部分,因此它是一个可以触发并等待布局更改的事件。就目前而言,sink
将您带出事件网络,在sink
操作完成后无法触发事件。我确实试图让sink
适应这样的事情:
sink' :: Frameworks t =>
w -> [Prop' t w] -> Moment t (Event t ())
sink' widget props = do
es <- mapM sink1 props
return $ unions es
where
sink1 (attr :== b) = do
x <- initial b
liftIOLater $ set widget [attr := x]
e <- changes b
return $ (\x -> unsafePerformIO $ set widget [attr := x]) <$> e
然而,unsafePerformIO
没有被执行。如何实现所需的行为,即允许通过Event
等待(wxHaskell)IO?
答案 0 :(得分:2)
基本上,您希望确保reactimate
中的IO操作按特定顺序执行?也就是说,您希望确保在小部件属性设置之后设置布局。
有几种方法可以指定顺序:
union
,unionWith
和/或collect
来确定同步事件的顺序。reactimate
按照Moment
monad中出现的顺序执行的事实。 (尽管严格来说,当您使用动态事件切换的observeE
组合子时,情况不再如此。)在您的特定情况下,可以按如下方式应用这些想法。
对于1,您可以创建包含IO操作的事件,并将其与稍后的布局相结合
sink' :: Frameworks t =>
w -> [Prop' t w] -> Moment t (Event t (IO ()))
sink' widget props = do
es <- mapM sink1 props
return $ foldr1 (unionWith (>>)) es
where
sink1 (attr :== b) = do
x <- initial b
liftIOLater $ set widget [attr := x]
e <- changes b
return $ (\x -> set widget [attr := x]) <$> e
对于2,您可以简单地使用普通的sink
函数,并确保最后设置布局。
do
sink widget1 [ visible :== bBool ]
sink window1 [ layout :== bLayout ]
monad中sink
函数的排序可确保最后设置布局。
另请注意,由于reactive-banana 0.7,您可以使用动态事件切换来为一组可变小部件建模。有关演示,请参阅BarTab.hs example。此示例还设置布局。
您表示在使用动态网络时遇到了MVar块。这可能是因为您以触发网络中另一个事件的方式创建窗口小部件。不幸的是,这在语义上是不合理的 - 它对应于取决于他们自己的未来版本的值 - 并且程序通过深入到底层来响应。