中州韵98五笔助手开发手记(1):结构设计


进度:功能设置页已完结

  • sample.png

构思:面向对象

程序开发是一个渐进的过程,所有内容都并非最终产品必然采纳的方式

首先,由于功能需求是特例化的,所以我们造了一个处理 Yaml 文档的轮子。所以,它必然是与前端是解耦合的。在整体上,就分成了 UI前端,与 数据后端

在开发过程中,前后端是即时通讯的,在发布产品时,将采用懒加载的方式:数据后端,仅在接到需要修改的触发指令后才会更新一次数据,以减少不必要的内存读写。

信使:逻辑比特

前端 的控制分类几大类,比如开关类,它就是 01,又或者是 truefalse。另外还有些是程序将会内置的可选择功能,比如候选标签的样式等等,这些在 yaml 文件中,是一些字符串式的参数,但由于它是固化在程序内的,可以编制成简单的 int Item 形参传递。最后是一些可能来自用户的字符串参数,预期插入到 yaml 文件的指定位置(当然用户不必关心插入的过程是怎样的)。

梳理这些需求,就会发现前后端通信其实是分几种情况的,但我们首先要解决的,是最基本的信使问题。在这里,采用了 Bit Operation 的办法。我们给前后端各自设置一个同类型的 unsigned long int 作为信使。它在 Qt 框架里是 8字节64比特,这个数量足以覆盖我们对 schema 的参数管理诉求了(其实 Schema 的参数项,也没 64 个那么多)。

前端每个控件,都有分配一个开关特定比特位的权限。这样,每次通讯的开销就非常少了。当前端的某个控件被改变时,它就点亮自己专属点位的信号灯。从而单次传参就能携带64个控件点位的变更信息,为懒加载模式提供了有力支持。

  • 针对开关控制,逻辑比特指示开或关

  • 针对其它控件,逻辑比特指示是否有更改

举例快捷键列表中特定行位如果有数据变更,那这次变更数据后,相应点位就变成1,表示灯已亮,有变动。于是后端动同步前端时,仅需下标访问,直接索取新参数,减少了遍历与对比判断。

类设计

YAML 处理类,作如下封装:

所有盛放数据的容器,统一采用顺序容器,在管理代码上比较方便。

首先是 IO 成员函数,采用 const bool & 1const bool & 0 的形参,来管理「读入」与「写出」。是吧,1I0O,长得还挺相像的。

在读时,要保留行数据中的空白符。YAML 的结构很好,参数多在尾部。根据 schema 的功能块,分别设置独立的容器,有些功能上固化的块儿基本是不变更的,变更的部分主要包括 switchesspellertranslator等,这些在直观上,似乎设为 QMap 更好,但是实际上参数变更的靶点一来在尾部,二来参数都是被读入到内存中,仅向用户展示功能名称的,使用关联容器后,并不能发挥其特长,因为在读上,它没有下标访问快,在写上,还要为之编写独立的 print 函数。

其中,key_binder 稍显特别,因为这块儿可能涉及频繁的改动,不过我们观察到,它的结构是非常有特点的:

key_binder:
  bindings: 
    - { when: has_menu, accept: Left, send: Up }
    - { when: has_menu, accept: Right, send: Down }
    - {accept: minus, send: Page_Up, when: has_menu}
    - {accept: equal, send: Page_Down, when: has_menu}
    - {accept: semicolon, send: 2, when: has_menu}
    - {accept: apostrophe, send: 3, when: has_menu}
    - {accept: space, send: Escape, when: composing}
    - {accept: space, send: space, when: has_menu}
    - {accept: Return, send: Escape, when: composing}
    - {accept: Return, send: Escape, when: has_menu}
    - {accept: "Control+Shift+4", toggle: zh_trad, when: always}
    - {accept: "Control+Shift+dollar", toggle: zh_trad, when: always}
    - {accept: "Control+Shift+F", toggle: zh_trad, when: always}
    - {accept: "Control+Shift+H", toggle: new_spelling, when: always}
    - {accept: "Control+Shift+J", toggle: new_hide_pinyin, when: always} 
    - {accept: "Control+Shift+K", toggle: single_char, when: always}

我们将之抽象为:{"toggle: zh_trad"_"Control+Shift+dollar"_always} ,即 {发送的命令,使用的热键,操控的范围}YAML类并不储存该类,这些内容作为结构化的数据储存在前端的 Model 中,在需要写出时,它的 IO 成员函数在恰当的时机将之逐行取出,并作格式还原。

于是我们就获得了一个性能优异、逻辑结构高效的抽象类,针对 RIME Schema 的结构,后期还有更大的宽容度,比如在功能参数相同的情形下,理解哪些是翻译器,哪些是正则行。后期加入文件监听后,就可以通过绑定 RIME 的现有指令,成为统盘接管 RIME功能参数 的全能助手。

外观缺憾

暂无精力研究 Qt 的样式表,在 LinuxMacOS 下,都很漂亮,但是在 Windows 下,界面有点复古。

  • sample.png
  • sample.png

文章作者: 五笔小筑
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 五笔小筑 !
评论