起因
最近在搞一个叫做芒果工具箱的项目,文档已经部署在这里了,大概是一个可以将任何用Python写的东西作为工具接入,然后从工具箱中启动的玩意。
设计工具箱的工具系统的时候,考虑的是应当能够简单地接入任何用Python写的工具,甚至应当能接入任何入口是Python脚本的工具,甚至应当能以Python脚本作为入口接入任何语言写的工具……
但是工具箱本体是用PySide6写的,这就意味着PyQt5/6和PySide2就可以洗洗睡了,不过大家都是Qt一家的,切换起来也比较方便吧。
那其他的窗口库呢?比如,Tkinter呢?
三年前的芒果帆帆
三年前是我刚刚开始自己研究Python的时候,代表作是三重烂尾的帆式MC启动器(Fan Craft Launcher)。在FCL烂尾的间隙,我曾经搓出来过一个密码解释器,作用是基于凯撒密码和维吉尼亚密码两种密码规范,实现两种加密和两种解密。
一开始我记得是命令行交互,后来学了点Tkinter,给它加了这个奇丑无比的GUI。
这个小垃圾玩意儿还是开源的,地址在Gitee上,因为当时不敢把这垃圾玩意放GitHub上丢人……然后现在发现我的GitHub没人看,我Gitee上三重烂尾的FCL倒是每几个月就有人来鞭一次尸……
后来很快,这个东西就连同我在Gitee上的三重烂尾的FCL一样,被我淡忘在茫茫的高中生活中了。等我再次想起来我曾经坚持Tkinter天下第一简单的时候还有几个Tkinter项目的时候,已经是2025年。
今天的芒果帆帆
正在思考一个严肃的问题:Qt窗口是一个事件循环,Tkinter也需要进入一个事件循环,这两个事件循环可以在一个进程中同时存在,即我是否能在一个进程中同时启动一个Qt程序和一个Tkinter程序呢?
首先我们知道,我们无法通过常规方式在代码中同时启动两个Qt程序或两个Tkinter程序,Tkinter中进入第二个事件循环时会让第一个循环卡死,Qt会告诉你“一个程序有一个QApplication就足够辣!”解决方案都是只保留一个循环,在一个循环中创建多个窗口,这也是很常规的、很容易想到的解决方案。
但我芒果帆帆就是喜欢剑走偏锋但我们就是要考虑特殊情况嘛,我们基于Qt技术的工具箱是否能简单地接入Tkinter程序,不试试怎么能知道呢?
工具加载模式
工具箱目前的工具加载方式是「直接import」,需要工具提供一个run.py
作为入口脚本,然后工具箱直接import
这个run.py
,执行里面的代码。
比如说,创建一个啥用都没有的空的Qt窗口,继承工具箱统一风格的FanWindow
的最小代码是这样的:
from ..public.public_window import FanWindow
if name == 'tool.exampleTool.run':
w = FanWindow()
w.show()
这里的if
分支就是程序入口,确保脚本只有在被工具箱导入时才启动这个窗口,因为必须要“蹭”工具箱的QApplication,无论如何都不应该被直接运行。
效果是这样的:
那如果用Tkinter创建一个空白窗口呢?创建一个空白Tkinter窗口同样只需要四行代码:
import tkinter
if __name__ == 'tool.exampleTool.run':
top = tkinter.Tk()
top.mainloop()
最后一行是进入Tkinter的事件循环,我们启动此工具得到一个标准Tkinter窗口:
然后就运行成功了。……?
没错,然后就运行成功了。按照工具箱的工具标准重新编写一个入口脚本,然后就可以简简单单地把「古典英语密码解释器」接入到芒果工具箱中了!
这个画风还蛮……不搭的……
联动感想
想不到(其实想到了)工具箱接入的第一个外部工具竟然是我三年前的一个小垃圾作品,也算是我一个人的梦幻联动了吧。
目前的联动还有一些问题,由于正在排查所以我也不好断言是Tkinter、Qt或是Python还是我个人的原因;另外由于这个网站是芒果帆帆的破站,我在公告里写了技术性的东西会往帆域而不是这里发,所以可以预想日后会有一篇关于PySide6与Tkinter联动的文章……
总之就是很奇妙的感觉吧,另外我也看到我那三重烂尾的Fan Craft Launcher竟然也能被人star了,这个也是以后的事情了……
嗯哼,慢慢来吧。