比起从 geeksforgeeks.com 抄那些常用的 Tk GUI 模式,我觉得开始着手提升这个模型的抽象度比较好…… 目前是简单支持了 Tk/T(hemed)Tk 两个widgets底层,我还打算支持GTK和WxWidgets
还有codegen…… (这样弄完了以后就可以给诸如C#,Java的语言生成初始化布局的代码 从树形结构前序遍历扁平化) 我觉得应该能行,但要花一些力气。
说起来PyDearGui也是挺不错的(ImGui 的主题系统和图表/绘制都很赞),不过它的作者因为是 C++ 实现,使用的定义式风格是
还有codegen…… (这样弄完了以后就可以给诸如C#,Java的语言生成初始化布局的代码 从树形结构前序遍历扁平化) 我觉得应该能行,但要花一些力气。
说起来PyDearGui也是挺不错的(ImGui 的主题系统和图表/绘制都很赞),不过它的作者因为是 C++ 实现,使用的定义式风格是
add_somewidget() 和 add_sameline() ,从语言角度看抽象层次更高但的确不如直接的vararg函数调用好看,不过目前 TkGUI 支持的是 verticalLayout/horizontalLayout (VBox&HBox) 所以应该也能用就是了Font,Color 之类的抽象也要弄…… 如果当真打算把这玩意做成框架的话
最重要的是,所有函数都要变成 class ,因为至少得支持 wx 和 GTK ,不可能滥用动态类型的,底层要改的也不少啊
而且貌似只有 Tk 这个框架需要 parent 变量,那这个玩意到底有没有用呢…… 要知道 parent 的 DSL (verticalLayout) 里是可以拿到 child 的,这么弄就没意思了,除非是在 Kotlin 里然后可以玩
如果你要专门为 Tk 弄一个不需要把 parent 给 partial apply 出来的 lazy constructor ,那又不可能(太麻烦)
反正这种冗余就是消除不掉,看看有 codegen 以后可以做什么弥补下吧……
最重要的是,所有函数都要变成 class ,因为至少得支持 wx 和 GTK ,不可能滥用动态类型的,底层要改的也不少啊
而且貌似只有 Tk 这个框架需要 parent 变量,那这个玩意到底有没有用呢…… 要知道 parent 的 DSL (verticalLayout) 里是可以拿到 child 的,这么弄就没意思了,除非是在 Kotlin 里然后可以玩
verticalLayout { add(wtfChild() ) } 这种弱智式的 parent 变量利用法……如果你要专门为 Tk 弄一个不需要把 parent 给 partial apply 出来的 lazy constructor ,那又不可能(太麻烦)
反正这种冗余就是消除不掉,看看有 codegen 以后可以做什么弥补下吧……
顺便给没接触过GUI的各位科普下目前我封装了的 tkinter widgets:
MenuItems: OpNamed(named), SubMenu, Sep(sep), CheckBox, RadioButton
Widgets(button/bar/line/box): button, radioButton, menuButton; scrollBar, progressBar; slider, text;
(string:)input, textarea, (number:)spinBox, (boolean:): checkBox, (listing:)listBox, comboBox;
menu, separator, canvas, treeWidget
Containers: HBox(horizontalLayout), VBox(verticalLayout); labeledBox, splitter, tabWidget, withFill, withScroll
其中控件里最常见的当属 text(文本), button(按钮), input(输入行), menu, scrollBar(滚动条), comboBox(多选框)
separator 是我自己写的(如果要移植到新底层,就得费好大力气调整类型...)(后来因为 TTk 里有又删了)
当然因为 Tk 做得比较纯,没有菜单栏和状态栏这回事,和 Gtk 的默认没有是一样的
容器里 labeledBox (分组盒) 和 tabWidget (Tk的Notebook ,就是多页视图) 很常见
现在很流行的布局方法是 grid ,但这里没有支持(其实很多Android应用用的grid也不多)
treeView 和 canvas 用处也蛮多,我想给接收 canvas 的操作们加一个 drawOn(widget, op_paint) ,就不用像 Java AWT 一样覆盖 onPaint 方法了,可惜要跨框架很麻烦
TreeView 的支持目前还不完全,因为它可以 multi-column 的,毕竟是一个 Model/View 的复杂数据视图,建模还需要时间
关于布局填充和顺序,如果要做一个全屏的 horizontalLayout(textarea,scrollbar) ,直接按顺序然后要 textarea fill 整个窗口是会盖住 scrollbar 的,所以只能把 scrollbar 放在前面然后用 _.fill(scroll, _.right, "y") (不过,scrollbar 本来就是 packSideFill, 只需修改 side 即可)
MenuItems: OpNamed(named), SubMenu, Sep(sep), CheckBox, RadioButton
Widgets(button/bar/line/box): button, radioButton, menuButton; scrollBar, progressBar; slider, text;
(string:)input, textarea, (number:)spinBox, (boolean:): checkBox, (listing:)listBox, comboBox;
menu, separator, canvas, treeWidget
Containers: HBox(horizontalLayout), VBox(verticalLayout); labeledBox, splitter, tabWidget, withFill, withScroll
其中控件里最常见的当属 text(文本), button(按钮), input(输入行), menu, scrollBar(滚动条), comboBox(多选框)
separator 是我自己写的(如果要移植到新底层,就得费好大力气调整类型...)(后来因为 TTk 里有又删了)
当然因为 Tk 做得比较纯,没有菜单栏和状态栏这回事,和 Gtk 的默认没有是一样的
容器里 labeledBox (分组盒) 和 tabWidget (Tk的Notebook ,就是多页视图) 很常见
现在很流行的布局方法是 grid ,但这里没有支持(其实很多Android应用用的grid也不多)
treeView 和 canvas 用处也蛮多,我想给接收 canvas 的操作们加一个 drawOn(widget, op_paint) ,就不用像 Java AWT 一样覆盖 onPaint 方法了,可惜要跨框架很麻烦
TreeView 的支持目前还不完全,因为它可以 multi-column 的,毕竟是一个 Model/View 的复杂数据视图,建模还需要时间
关于布局填充和顺序,如果要做一个全屏的 horizontalLayout(textarea,scrollbar) ,直接按顺序然后要 textarea fill 整个窗口是会盖住 scrollbar 的,所以只能把 scrollbar 放在前面然后用 _.fill(scroll, _.right, "y") (不过,scrollbar 本来就是 packSideFill, 只需修改 side 即可)
上面的窗口只有第一个是我自己写的,canvas/tree 还有那个异步拿 COVID-19 统计数字JSON的 都是网上抄的... 不过说实话他们的文章写得很好,但代码有时候真不敢恭维emm
duangsuse::Echo
相信我,这玩意拿来做预览也不错…… 不过还是要尝试下兼容 GTK 什么的,动态类型脏就脏了,反正只要开发者注意好 框架做基本支持 动态类型也没关系,何况还有 codegen 可以用呢。
codegen 已经完成了,还算顺利(并不)
为此我花了昨天下午到今天下午的所有时间,而且昨天熬夜到12点(第三天了)
使用的原理很简单,就是 value-variable substitution , 我利用 Python 的动态特性创建了 call, callNew, invoke 等方法,实现这些函数的语义并且在请求代码生成,就实现了复用
但就在刚刚遇到了一个怪事使我以为 Python 有 bug (看起来一个方法调用没成功执行,事后发现是头部的 if not: return 时序没注意到以及用print调试时看走眼了)
不过这件事也使我找到了 id_map/id_set (object id mapping) 的正确写法不是先 try: except TypeError: return _id.get(key) 而是把 key 直接映射到 id ,所以磨叽了一个半小时后,完成。
下一步可能是收尾这个特性(还要考虑拿它来自动为GTK/Wx忽略第一个 parent 参数,虽然我也不想这么干emmm) 然后发布
为此我花了昨天下午到今天下午的所有时间,而且昨天熬夜到12点(第三天了)
使用的原理很简单,就是 value-variable substitution , 我利用 Python 的动态特性创建了 call, callNew, invoke 等方法,实现这些函数的语义并且在请求代码生成,就实现了复用
但就在刚刚遇到了一个怪事使我以为 Python 有 bug (看起来一个方法调用没成功执行,事后发现是头部的 if not: return 时序没注意到以及用print调试时看走眼了)
不过这件事也使我找到了 id_map/id_set (object id mapping) 的正确写法不是先 try: except TypeError: return _id.get(key) 而是把 key 直接映射到 id ,所以磨叽了一个半小时后,完成。
下一步可能是收尾这个特性(还要考虑拿它来自动为GTK/Wx忽略第一个 parent 参数,虽然我也不想这么干emmm) 然后发布
这么一看我就是太弱智了才在codegen支持上花这么多时间,明明是一个毫无难度的东西,竟然浪费了我那么多看片的时间,罪过罪过…… 欲哭无泪
这个算法的名字就是 value-name substitution ,我一开始就明白,却想了半天才得出结论
对了,生成的代码貌似是按后序遍历排序的,尽管这个是基于副作用build str
这个算法的名字就是 value-name substitution ,我一开始就明白,却想了半天才得出结论
对了,生成的代码貌似是按后序遍历排序的,尽管这个是基于副作用build str
#Python 真是无法保证这样复杂的时序写对…… 在有了Kotlin以后我不会在区间开闭上出错 但时序变量更新还真不能保证。(据说bug还是因为我顺手简化"无用赋值"导致的) 我不想写下去了,花了好大精力还熬了三天夜……刚刚有点好转
总感觉可以优化,总感觉看着让人觉得要删掉,可按顺序看看倒也没什么,可是关键在于把它删掉看着也没什么…… 直觉要好啊
注:是指
注:是指
expr = get() ; if (expr == null) { expr = get1(); if (expr != null) bla() } 这种看起来怎么这么相似的我准备发布了,发布后就会死掉。 不过对我来说这个无所谓(
加了一些东西(command 参数的 self 的编号, dict.findKey) 又因为实现不了而删了,心里不开心,现在放假了。
加了一些东西(command 参数的 self 的编号, dict.findKey) 又因为实现不了而删了,心里不开心,现在放假了。