duangsuse::Echo
709 subscribers
4.23K photos
127 videos
583 files
6.43K links
import this:
美而不丑、明而不暗、短而不凡、长而不乱,扁平不宽,读而后码,行之天下,勿托地上天国。
异常勿吞,难过勿过,叹一真理。效率是很重要,盲目最是低效。
简明是可靠的先验,不是可靠的祭品。
知其变,守其恒,为天下式;穷其变,知不穷,得地上势。知变守恒却穷变知新,我认真理,我不认真。

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
总感觉可以优化,总感觉看着让人觉得要删掉,可按顺序看看倒也没什么,可是关键在于把它删掉看着也没什么…… 直觉要好啊

注:是指 expr = get() ; if (expr == null) { expr = get1(); if (expr != null) bla() } 这种看起来怎么这么相似的
This media is not supported in your browser
VIEW IN TELEGRAM
第一个从生成的代码创建出的Tk frame
This media is not supported in your browser
VIEW IN TELEGRAM
太赞了!我居然做出了这种框架…… 等等,这样又如何呢emm
我准备发布了,发布后就会死掉。 不过对我来说这个无所谓(
加了一些东西(command 参数的 self 的编号, dict.findKey) 又因为实现不了而删了,心里不开心,现在放假了。
草这样不至于吧, Python 里 [for] {for} 都是对应数据的 genexpr ,没想到 () 居然不是 tuple 的 genexpr ……
类似表达式的后序遍历果然不行,需要的变量定义顺序很不对啊(而且这里好像不支持属性访问语法一样)...
看来只能用很脏的全局变量了…… 反正组件树是后序遍历的,那它依赖 但要调用创建它 所以必须提前的东西 就只能用全局变量了…… 不知道会不会有数据竞争之类的问题(但如果有说明应用的代码太飘了……)

有了这个以后,不知道 Codegen 的 autoExpr 该不该留,我想如果出于一些非常迷的目的(比如说 简写法),删代码真和割肉一样斟酌。。。
啊这个bug真的太艹了...
This media is not supported in your browser
VIEW IN TELEGRAM
不想写了,反正别的我是不写了。写完就放假
...服了,用这样脏的修改也会有这样的结果……
做到七点半,就不修了睡大觉。 这个问题是蛮特殊的,在构造器调用里出现,恰巧我没有为赋值的情况考虑。 何况 codegen 本来就是为视图树的后序遍历情况考虑的,根本没想某些构造器还有创建窗口副作用…… 不过我突然想到一个 workaround 估计还可以
真无语了,吃饭去
This media is not supported in your browser
VIEW IN TELEGRAM
马上 TkGUI 就要进入 PyPI 了,真棒。可我一点也不开心。
真的不知道这样瘸腿的设计如何做到正确codegen…… 一般来说是有个区域限制的吧,比如某个 window 内codegen就只能访问它的上下文,所以不用处理命名冲突,但我对这个奇葩代码生成方法理解的本来就不深刻,只是想拿它简化代码而已…… (而且我真是不想加任何限制虽然原理的编程建模本身有功能限制)
真不知道这个框架什么时候会变成 Python 里最好的,感觉可以拼一下?喵。

https://github.com/duangsuse-valid-projects/TkGUI
今天终于可以早点睡了……(而且以后几天都不会有出产,真可惜)
下面来列举一些 Python 的 GUI 工具/框架,从 PyPI 找的

https://github.com/alejandroautalan/pygubu
Pygubu is a RAD tool to enable quick and easy development of user interfaces for the Python's tkinter module inspired by Glade. (UI Designer)

https://pypi.org/project/sgui/
A simple GUI library for Python, wrapper around Tkinter In the future, backends for other languages like [pyside2](http://wiki.qt.io/Qt_for_Python) may be added.
mainBox = sgui.VBox(window)
sgui.Label(mainBox, string = "Text")

(我也一样!反正我是真想加GTK的后端,因为它好看啊,但不好写...)

https://pypi.org/project/ttkwidgets/
A collection of widgets for Tkinter’s ttk extensions by various authors (updated)

https://pypi.org/project/uielem/
wrapper over Tkinter for more Pythonic UI building
uiroot = UI(Tk, name='root', title='Kanban', children=[UI(Button, text='Add item', command=add)])
uiroot.makeelem()
uidict["root"].mainloop()

不太好看,不过我估计这个作者纯元编程封装很省力。(还好咱加了代码生成后也元编程了,而且还0抽象开销+代码生成本身无需重复代码,动态类型才叫Pythonic。嘿嘿)

https://pypi.org/project/tkintertoy/
Tkintertoy was designed to be a easy to use GUI library based on Tkinter. It was intended for "young"
gui = Window()
gui.setTitle('My First Tkintertoy GUI!')
gui.addEntry('name', 'Type in your name')
gui.plot('name', row=0)

这个虽好但不喜欢,如果光说。 看后面有个严重减分项:
while True:
gui.waitforUser()
if gui.content: gui.set('welcome', 'Welcome ' + gui.get('name'))

如果从视图定义方式来看,类似 ImGui :
https://pypi.org/project/dearpygui/
add_text("Hello world")
add_button("Save", callback="save_callback")

https://github.com/dholm/simpleguitk/
http://www.codeskulptor.org/

SimpleGUITk is a wrapper for the CodeSkulptor SimpleGUI API using TkInter

frame = simplegui.create_frame("Home", 300, 200)
frame.add_button("Click me", click)
frame.set_draw_handler(draw)

支持浏览器环境和 paint 事件,加分!

https://github.com/TaylorSMarks/FinGUI

A Pythonic Wrapper for Tkinter
from fingui import Entry
e = Entry()
e.set('Hello World!') # no need to call mainloop

感觉对全局环境和 mutate(set) 方法的依赖太严重,不作评价

https://bitbucket.org/svenrahmann/geniegui/src/master/geniegui.py
Python GUI generator. Automatically generate tkinter GUI applicatons from argparse objects.
有意思。但没有实例和截图的项目别人是不会看的。

https://pypi.org/project/tkup/
tkup is a thin wrapper around standard Tkinter widgets, allowing you to write code that visually reflects the widget hierarchy, helps you use normal Tkinter in a streamlined way.

这个开发者的思想和我一样都是定义式,但他选的方式我不太喜欢,毕竟 vararg 是几乎什么语言都有的,但 with (类似try-with-resource但有__enter__事件) 可不是哪都能移植,而且它还必须用副作用构造控件树

https://github.com/Mandera/generalgui
Extends and simplifies tkinter functionality with built-in QoL improvements.
是基于 App, Page, Element 的 Tkinter 封装,它重命名了一些控件并且简化封装grid等,不是所有控件都支持。

https://github.com/duangsuse-valid-projects/TkGUI
Declarative tkinter wrapper for Python, features quick prototype and (dynamic type, "implicit") codegen.

我最喜欢的当然是自己造的了…… 以后codegen完善了就能缓存结果降低开销(zero cost abstraction! 虽然是Python...),而且支持更多 GUI 框架后可以跨语言代码生成, 虽然估计不会再动codegen部分

https://github.com/Akuli/teek
Teek is a pythonic and user-friendly alternative to tkinter

Teek 是把 tkinter 整个重写了一遍,而且从 event loop 支持了视图的异步变动, TkGUI 从里面抄了不少东西,不过没抄不区分 Tk main 和 Toplevel 窗口的,之前我觉得没必要不区分(所以只能从 main 窗口 quit 什么的...),以后如果重写我会接受平等窗口的概念 (不像 Tk 到处 master slave ,呵呵)

https://uiutil.readthedocs.io/en/latest/summary.html dead?
duangsuse::Echo
真无语了,吃饭去
昨天晚上想了一下,发现其实只是一个小地方早就有bug,现在暴露出来了而已。 #Python #gui #cs
完成后我会进一步拆分出 ui/widgets/utils 模块以方便未来的 GTK 支持 ,还会加入 grid(row(a, b, c) ) 控件。(如果以后能加入 Glade/PyGUBU XML 的 compiler 就更好了,但纯DSL也不错)

因为 Tk 的 Frame 没法 scroll 而无法选择用类似DOM的appendChild替换ListView ,因为不想写 "Adapter" 什么的所以讨厌类似 Model/View 的设计模式(当然Qt的MV也是很巧妙的,兼顾了 index+delegate) ,想了一会用受管的 "View" 也不一定难看: ListView<String> { Text(it) } 这样不就是定义式且和 DOM 的 ul/div 一样容易了么... 而且一样可以用 DSL 风格批量创建初始项 (不愧是最赞的 Kotlin ,写什么都好看,设计哲学甩 Ruby 半条街 Python 两条街 ❤️) (老实说 Python 创造时也是蛮有抱负的,还有现在被菜鸟挤爆的"Pythonic": import this ,当然它火所以质量下降也不能怪它,可是到现在我真的欣赏的也只因为它是唯一支持 layout 缩进语义的工业语言,我觉得好语言不应该可以表达出烂代码///)

不过,其实我并不喜欢 Python (而且 Py 支持的 vararg kwargs 现在 Ruby 也支持了) , 虽然它写的代码简洁无需 enddel [:] global nonlocal 之类的东西太难看了,有些简化命名我也不太欣赏,面向对象模型也和 JS 的一样迷
但这次利用在 Py 里无重复为定义式框架实现 codegen ,和多backend 但无需自有抽象的 (embed.)DSL 也的确让我看到了动态类型的一些好处,如果你只想省时间的话

其实编译期和运行期也不是相互孤立的,在动态语言里,从解释实现的角度他们很可能混在一起无法区分;
但如果你的程序有代码生成的特性,就会发现如果把编译期和运行期结合在一起,很多看起来在"编译期"无法得出的数据(比如 flatten 一个嵌套结构),其实都是可以"静态"拿到的,因为编译期就是代码生成程序的运行期,而编译期和运行期区分的本质在于对数据的依赖(例如无副作用的函数有常量参数就可以编译期计算;或属 input() 的运行期数据),而并非"它是不是常量"(见C++ constexpr) (但C++弄得太麻烦)。

这一点有不少框架都用到了。比如几乎被历史抛弃的 Butterknife... 其实就可以用 annotation processor 和 syntax tree 的 reflect 做到动态生成绑定 inner class ,但它们做的都不如这次写的 Python 隐式 codegen 明显,咱只是把 call/callNew/invoke 和 setAttr/setItem 操作给替换一下就实现了全框架定义式转表述式、降低抽象开销的目的。(因为 Python 本身就没有编译期无需分割出codegen代码用Visitor访问语法树 而只用最小化的"给某被引一个名字"从而"完美兼容constexpr式计算"而已,顺便: Codegen 类本身也是可复用的,虽然我对这一点抱疑。)

有的时候代码生成这种扩展特性不是必须的,但实现它们也有利于对框架功能的理解(虽然我懒得标注类型...顺便:其实我觉得 string:String 完全应该用 :String 替换的,讨厌余赘表达,emm),正如我在写 ParserKt 的时候除了必要的 read 还配对定义了 show 操作一样。(这在 Kotlin lib 里真不常见,因为它是"函数式语言的专利",但我觉得关键在于定义式的高层建模思想,不强求写出实现法 可读性、可扩展性都会更好)
草,所以这个到底是什么鬼,花了我40分钟调试 因为不知道为什么结果不和我预期的一致,后来才发现是有个赋值…… 应该说这些赋值真是麻烦