【问题标题】:Handling mutually recursive GUI widgets with reactive-banana使用 reactive-banana 处理相互递归的 GUI 小部件
【发布时间】:2012-11-04 01:41:19
【问题描述】:

我正在寻找一个库来在 GLFW 和 OpenGL 之上编写 GUI。我这样做是因为我对常见的 UI 库绑定感到不满意,我觉得这些绑定过于必要,而且我还希望严格控制我的 UI 的外观和感觉。我想要一种定义 UI 的声明性方法。我正在试验反应香蕉(和暂时反应香蕉wx),看看它是否满足我的需求。我在定义递归小部件时遇到问题。这是我最简单的测试用例:

  • 显示计数器的文本小部件。
  • 增加计数器的按钮小部件。
  • 当计数器为 0 时处于非活动状态(因此它变灰并且根本不响应输入)的按钮小部件,否则处于活动状态并将计数器重置为 0。

第一个和第三个小部件具有递归关系。第一个小部件直观地是stepperunion 的两个按钮提供的事件。但是,重置按钮是计数器的fmap,然后事件流依赖重置按钮!该怎么办?

除了这个问题之外,我还担心事件处理:由于我想在我的代码中处理设备输入和输入焦点,而不是依赖于框架,因此我认为以可扩展的方式正确调度事件存在困难。理想情况下,我会定义一个data,它封装了小部件的层次结构,一种在元素之间安装事件回调的方法,然后编写一个遍历该数据结构的函数,以定义设备输入处理和图形输出。我不确定如何获取事件流并将其拆分为可以合并事件流一样容易。

【问题讨论】:

    标签: user-interface haskell frp reactive-banana


    【解决方案1】:

    允许递归,只要它是BehaviorEvent 之间的相互递归。 Behaviors 的好处是在更新时对它们进行采样将返回旧值。

    例如,你的例子可以表示如下

    eClick1, eClick2 :: Event t ()
    
    bCounter :: Behavior t Int
    bCounter = accumB 0 $ mconcat [eIncrement, eReset]
    
    eIncrement = (+1)      <$ eClick1
    eReset     = (const 0) <$ whenE ((> 0) <$> bCounter) eClick2
    

    另见问题"Can reactive-banana handle cycles in the network?"


    至于您的第二个问题,您似乎正在寻找函数filterE 及其表亲filterApplywhenE


    至于你的总体目标,我认为它是相当雄心勃勃的。从我迄今为止获得的少量经验来看,在我看来,绑定到现有框架与在 FRP 中制作“干净状态”框架完全不同。最有可能的是,仍然潜伏着一些未被发现(但令人兴奋!)的抽象。我曾经开始编写一个名为 BlackBoard 的应用程序,其中包含一个关于时变绘图的很好的抽象。

    但是,如果您更关心结果而不是冒险,我会推荐一种保守的方法:以命令式样式创建 GUI 工具包,并在此基础上挂钩 reactive-banana 以获得 FRP 的好处。

    如果您只希望任何 GUI,我目前专注于将Web 浏览器作为GUI。这里有一些preliminary experiments with Ji。与 wxHaskell 相比的主要好处是它更容易启动和运行,任何 API 设计工作都将使广大受众受益。

    【讨论】:

    • 如果你在 Event monad 中怎么办?我很担心,因为它没有用于值递归的 MonadFix,因此在存在动态事件切换的情况下无法表达相同的递归。当然,我仍然对所有公开的例子并不完全满意。
    • 至于我的第二个问题:filterE 等。我认为,在可扩展性方面朝着错误的方向工作。他们从一个事件中拉出来,这似乎很麻烦。比如说,我们有一个带有用于键盘焦点的光标的 gui 小部件的树形结构。我们希望将eDeviceInput 事件转换为基于该光标的事件。使用filterE,每个接收事件流都必须在窗口小部件树上执行自己的过滤器,并且还要知道它在树中的位置,这使得布局转换和动态事件切换变得很麻烦。
    • Event 类型不是单子。您可能是指Moment monad?正如您所料,它是MonadFix 的一个实例。
    • 好吧,由于filterE 是从事件流中删除事件的唯一方法,因此您必须以一种或另一种方式使用它。但是您可以添加其他信息并对其进行过滤。例如,您可以使用从树计算的小部件标记eDeviceInput 的每个出现,然后让各个小部件简单地在标签上过滤。这至少避免了为每个单独的小部件进行昂贵的树计算的需要。
    • 但你是对的,filterE 的情况类似于模式匹配与模式保护。我建议暂时使用它。如果它成为问题,我可以添加某种高效的“扇出”功能,只是我还没有找到一个优雅的通用 API。
    猜你喜欢
    • 1970-01-01
    • 2012-11-14
    • 2015-11-25
    • 1970-01-01
    • 2015-12-31
    • 1970-01-01
    • 2013-02-16
    • 1970-01-01
    • 2011-03-25
    相关资源
    最近更新 更多