Clojure:如何构建桌面UI



我正在尝试为原理图,布局,绘图内容设计桌面UI。 只是从实际的软件设计师那里寻找高级建议。

假设内存中的"数据库"(所有用户数据的任意深度的clojure映射,以及应用程序首选项等的另一个映射),我正在研究如何对这些进行模型-视图-控制器操作,其中数据可以由以下任何一个或多个渲染和修改

  1. 显示单个参数(如框宽)的独立文本字段。
  2. 一种"检查器"类型的视图,显示所选对象的多个参数,例如框的宽度、高度、颜色、复选框等。
  3. 一种表格/电子表格类型的视图,显示多个对象(可能是整个数据库)的多个参数
  4. 整个事物的图形呈现,例如原理图和布局视图。

修改其中任何一个都应该立即显示在所有其他活动视图中,包括文本和图形,而不是在单击"确定"之后......所以不允许模态框。 如果由于某种原因,表格视图、检查器视图和图形呈现都在视图中,则以图形方式拖动框的一角应立即显示在文本中,等等。

有问题的平台是JavaFX,但我希望在UI和其他所有内容之间完全分离,所以我想避免JFX意义上的bind,因为这将我的设计数据与JFX属性紧密联系在一起,增加了模型的颗粒度,并迫使我在处理数据的标准clojure函数之外工作, 和/或与整个getValue/setValue世界打交道。

我仍然假设至少一些有状态/可变性,以及内置 Clojure 功能的使用,例如在 atom/var/ref 上add-watch并让运行时发出依赖函数的能力。

特定于平台的交互将与实际 UI 紧密相关,例如ActionListener和处理ObservableValue等,并将尝试最大限度地减少对 JavaFX Property等内容对实际应用程序数据的依赖。 我不是在为此娱乐FRP。

我不介意扩展JFX接口或编写自己的协议来使用特定于应用程序的defrecord,但我更希望应用程序数据保持为直接的Clojure数据,不受平台的玷污。

问题是如何设置这一切,最接近不可变模型。 我看到几个选项:

  1. 细粒度:每个参数值/基元(即长整型、双精度型、布尔值或字符串)都是一个原子,每个可以修改值的视图都可以在数据库中根据需要"到达"以更改值。 这可能会很糟糕,因为可能有数千个单独的值(例如手绘曲线上的点),并且需要大量(deref...)垃圾。 我相信这就是 JFX 想要这样做的方式,在叶节点等处使用巨大的属性数组,感觉很臃肿。 使用这种方法,似乎并不比仅仅用Java/C++编写它更好。
  2. 中粒度:数据库中的每个对象/记录都是 Clojure 映射的一个原子。 当地图的任何一个值发生更改时,将替换整个地图。 需要处理的总原子更少,并且允许例如为各种事物使用长长的直截了当的数字数组。 但是,当数据库中的某些对象比其他对象需要更多的嵌套时,这变得很复杂。
  3. 粗粒度:只有一个原子:数据库。 每当发生任何更改时,都会替换整个数据库,并且每个视图都需要重新呈现其特定部分。 这感觉有点像用锤子拍苍蝇,而朴素的实现需要一直重新渲染所有内容。 但我仍然认为这是最好的权衡,因为任何原语都有来自根节点的明确访问路径,无论是在每个基元级别还是每个记录级别访问。

我还需要能够多次实例化一个数据模板。 因此,例如,如果用户更改了在多个位置使用的符号或形状,则单个编辑将应用于所有位置。 我相信这也需要某种类似"指针"的行为。 我想我可以将原子存储到模型中,然后根据需要实例化,它可以在上述任何颗粒模型中工作。

还有其他方法吗? 尝试用函数式语言做一个类似GUI编辑器的工具是愚蠢的吗?谢谢

我认为使用函数式语言来做类似GUI编辑器的工具并不愚蠢。但我不能声称对你的问题有答案。以下是一些可能对您的旅程有所帮助的链接:

  1. 斯图尔特·塞拉 - 组件恰到好处的结构
  2. Chris Granger - Light Table:解释Light Table(源)的结构。
  3. Chris Granger - The IDE as a Value:与上述视频相关的博客文章
  4. Conal Elliott - 有形函数式编程:使用函数式响应式编程来创建可组合的UI,但他的代码是用Haskell编写的。
  5. Nathan Herzing & Chris Shea - 帮助选民使用基座、Datomic、Om 和 core.async
  6. David Nolen - 比较素养编程:显示所有使用 core.async 来简化 ClojureScript 中的 UI 编程。此处的想法可以在桌面 UI 中使用。
  7. Rich Hickey - The Language of the System:Clojure的创建者关于系统编程的惊人演讲。

Erik Meijer 有一个关于函数式代码与命令式代码的好引述:

。无论是Haskell,C# Java,F#,Scala,Python,PHP,想想拥有与外部世界交互的命令式代码海洋的想法,并且那里有纯代码的孤岛,您可以在其中以纯粹的方式编写函数。 但是你必须决定岛屿有多大,海洋有多大。但答案从来都不是只有岛屿或只有海洋。一个好的程序员确切地知道正确的平衡。