PyGUIAdapter:一个将“任意”Python程序转换为GUI应用的库
一、背景
在Python开发中,GUI程序的开发一直是一个比较难办的问题,为了照顾到那些不习惯使用命令行的用户,我们常常需要为我们的python程序套上一层GUI的壳。Python的GUI框架还算是比较丰富的,有内置的tk,也有像wxWidgets、GTK、QT这样成熟的GUI框架的绑定,借助这些框架,完全可以为任何Python程序构建出合适的甚至是花里胡哨的图形用户界面,但问题在于:如果你是一个GUI方面的新手,学习一种GUI框架无疑将引入巨大的学习成本。很多时候,我们只是想给我们写的小工具套一个图形化的外壳而已,不等于我们真的想去写大量的GUI代码,事实上,手动去处理界面的状态、交互、事件、数据等确实是一件比较折磨人的事情…
那么,有没有一种工具,可以让我们尽可能多地关注功能的实现,而它在背后偷偷地帮帮我们处理好所有(或者是)大部分界面相关的细节,让我们可以“无痛”地为我们的程序套上一层图形界面的“外衣”,(当然,没有那么花里胡哨也可以)。经过一番研究,我发现,嘿还真有。现成的,比较成熟的一个解决方案是Gooey,一个号称可以 “Turn (almost) any Python 3 Console Program into a GUI application with one line” 的Python库。
二、Gooey以及为什么没有选择它
Gooey 是一个python库,目前在 github上20.3K star,是一个比较受欢迎的项目。
它使用wxWidgets
作为底层GUI框架,可以将几乎所有python命令行程序转换为GUI程序,它生成的界面如下图所示:
它的原理简单来说,就是把命令行解析器(argparse)解析到的命令行参数转换成对应的输入控件,然后通过这些控件,接受用户的输入。它的使用也确实足够简单,有时候一个装饰器@Gooey
就解决了问题。
但是,我最后还是没有选择使用Gooey
,这里有几个原因:一是在我的机器上Gooey生成的界面总感觉有些卡卡的(不知道是不是因为wxWidgets
在Windows平台上有些“水土不服”);二是在高分屏上,Gooey界面上的文字总是有些模糊(找了一圈没找到开启high dpi的接口);三是Gooey这个库好久没有更新了,它的最后一次提交已经是在两年前。
除了上面这几个原因,还有一个很重要的因素,那就是,Gooey
帮我们摆脱了GUI代码不假,但我们还是要写argparse代码。
不想写GUI代码≠想写命令行代码(嘿嘿,公式做题就是快)
那么,有没有那么一种可能,我是说可能,存在那么一种东西,可以歘的一下,把任意一个函数转换成图形界面,它的参数变成了输入控件,点一下按钮,就可以运这个函数。如果存在这样的东西,那么不就解决了我们既不想写GUI代码,也不想写命令行代码的矛盾了吗?
很遗憾的是,我并没有发现这样的存在。既然如此,本着没有轮子,那就自己造一个的思路,我开启了一个新的项目——PyGUIAdapter。
三、自己手搓一个吧:PyGUIAdapter的诞生
从功能上看,PyGUIAdapter
`和`Gooey
有些类似,但在原理上,二者存在很大区别。
如上文所讲,Gooey
是面向命令行的,它主要是做了把命令行参数转化为输入控件的工作。
而PyGUIAdapter
从一开始就是面向函数的。我想,既然都打算使用图形界面了,那么干嘛还需要argparse
这个中间商赚差价呢。直接把要实现的功能封装成函数,把用户输入对应为函数的参数不就行了吗。这样,我们只需要解析函数,提取它的参数,然后生成对应的界面控件就可以了,是不是非常简单呢?
为了实现从函数到控件的映射,我另写了一个库function2widgets,它是PyGUIAdapter的基础,主要的功能就是从函数签名和函数的文档字符串中提取信息,通过一系列规则,为函数每个参数生成对应的控件。它默认从函数参数的类型推断其对应的输入控件,如:
参数类型 | 控件类型 |
---|---|
int | IntLineEdit |
bool | CheckBox |
float | FloatLineEdit |
str | LineEdit |
list | ListEditor |
dict | DictEditor |
tuple | TupleEditor |
datetime | DateTimeEdit |
date | DateTime |
time | TimeEdit |
Literal | ComboBox |
Any | JsonEditor |
除了以上控件,function2widgets还实现了许多其他控件,如Dial、Slider、FilePathEdit、DirPathEdit、CheckBoxGroup、RadioButtonGroup、PlainTextEdit等等。
PyGUIAdapter在设计之初就考虑到了扩展性和灵活性的问题,我们既可以依赖内置的规则,由function2widgets库自动推导函数参数所对应的控件类型;我们也可以通过一些方法,手动指定参数的控件类型,同时配置控件的属性,如我们可以手动设置LineEdit的占位符文本(placeholder)、FilePathEdit的文件名过滤器(filters)等等,function2widgets实现的每种控件都有大量可配置的属性。
对了,PyGUIAdapter
与Gooey
的另一个区别是,PyGUIAdapter基于PyQT6,通过它生成的界面对high dpi更加友好,而且从流畅度上看,PyQT6似乎也要更好一些(至少在我的机器上是这样的)。
四、PyGUIAdapter的基本使用
PyGUIAdapter的使用非常简单,最少只需要三行代码就可以把一个python函数转换为GUI应用。
下面,是一个简单的使用指南。
1.安装
从pypi安装PyGUIAdapter最新版本:
使用pip:
pip install pyguiadapter
使用poetry:
poetry add pyguiadapter
2. 将需要提供给用户的功能封装成一个函数
假设我们有这么一个函数,我们忽略它的具体功能,我们只需注意到,它需要输入4个参数,每个参数都用类型标注语法标注了参数类型。
def create_file(path: str, filename: str, content: str, overwrite: bool = False):
path = os.path.join(path, filename)
if not os.path.isfile(path) or overwrite:
with open(path, "w", encoding="utf-8") as f:
f.write(content)
return True
return False
3.三行代码(忽略import),为这个函数创建GUI界面
from pyguiadapter.adapter.adapter import GUIAdapter
gui_adapter = GUIAdapter()
gui_adapter.add(create_file)
gui_adapter.run()
完整代码如下:
import os.path
def create_file(path: str, filename: str, content: str, overwrite: bool = False):
path = os.path.join(path, filename)
if not os.path.isfile(path) or overwrite:
with open(path, "w", encoding="utf-8") as f:
f.write(content)
return True
return False
if __name__ == "__main__":
from pyguiadapter.adapter.adapter import GUIAdapter
gui_adapter = GUIAdapter()
gui_adapter.add(create_file)
gui_adapter.run()
运行这个程序,我们就得到了以下界面:
是不是非常简单,我们没有写一行gui代码和argparse就得到了一个不错的gui界面。
4.一些常用的自定义方法
当然,你可能会提出,根据语义,path使用一个专门编辑路径的控件更合适,content用一个多行文本控件会更好,每个参数名称如果可以自定义就好了,如果有详细的说明就更好…
这一切,都是可以实现的,这里提供一种常用的自定义方法(更多自定义的选项和方法会有单独的文章进行介绍,也可以直接阅读PyGUIAdapter仓库中examples/下的示例源代码,这些示例几乎涵盖了PyGUIAdapter使用的每一个方面)。
为了进行自定义配置,我们需要借助函数的文档字符串,就是函数体开头使用三个引号包裹起来的多行字符串:
def foo():
"""
这里就是函数foo的文档字符串
"""
pass
PyGUIAdapter通过文档字符串中@widgets和@end标记包裹起来的一段toml 格式的文本来对参数的控件进行配置
比如要指定path参数的控件类型和控件属性等,可以像下面这样做:
"""
...
@widgets
# 要应用自定义配置的参数的名称
[path]
# 指定控件类型
widget_class="DirPathEdit"
# 指定界面上显示的参数的名称
label="文件保存目录"
# 指定参数的描述
description="请选择生成的文件的保存目录"
# 配置控件的其他属性
# 具体可配置的属性取决于控件的类型,可参考function2widgets下的XXXArgs类,其中XXX为控件的类名
# 例如DirPathEdit对应的就是DirPathEidtArgs类
placeholder="选择文件保存的目录"
start_dir="./"
....
@end
"""
除了可以在@widgets和@end块中指定参数的描述文本,PyGUIAdapter还会从 ReST、Google、Numpydoc-style以及Epydoc风格的文档注释中提取参数的描述信息,如:
def foo(a: int):
"""
:param a: 这是参数a
"""
下面,我们来改造一下上面的例子,使得生成的界面用户体验更好:
import os.path
def create_file(
path: str,
filename: str,
content: str,
overwrite: bool = True,
):
"""
这是一个演示程序,用于演示<b>PyGUIAdapter</b>的功能,这段文字会被提取为函数的Document并显示在界面上。
:param path: <b>生成文件的保存的目录,若为空则保存到当前路径下</b>
:param filename: <b>生成文件的文件名称。注意:<font color=red>不可为空!</font></b>
:param content: <b>生成文件的内容</b>
:param overwrite:
:return:
@widgets
[path]
widget_class="DirPathEdit"
label="保存路径"
button_text="选择目录"
placeholder="选择文件保存的目录"
[filename]
label="文件名"
placeholder="生成文件的名称"
clear_button=true
[content]
widget_class="PlainTextEdit"
label="文件内容"
placeholder="生成文件的内容"
[overwrite]
label=""
text="是否覆盖现有文件?"
@end
"""
if not path:
path = "./"
if not filename:
raise ValueError("文件名不可为空,请指定文件名称")
path = os.path.join(path, filename)
if not os.path.isfile(path) or overwrite:
with open(path, "w", encoding="utf-8") as f:
f.write(content)
return True
return False
if __name__ == "__main__":
from pyguiadapter.adapter.adapter import GUIAdapter
gui_adapter = GUIAdapter()
gui_adapter.add(create_file)
gui_adapter.run()
经过配置,界面变成了下面这个样子,相比之前,用户体验提升了不少:
create_file() 函数文档字符串中的描述也被正确提取出来,显示在Document区域中:
现在,可以在控件内填入参数,然后点击Execute按钮运行这个函数了:
可以看到,函数内的异常也被正确地捕获,并通过对话框的方式提示给用户了,没错,这就是PyGUIAdapter进行参数校验的方式,对于不符合要求的参数,直接在函数内部抛出异常就可以了,非常符合我们写程序的直觉。
五、小结
PyGUIAdapter的使用非常简单,但是提供的功能和可配置的选项非常丰富,上面本文提到的那些仅仅是非常小的一部分,除了这些,你可以:
- 自定义窗口和控件的外观、样式、图标、文字等
- 自定义对话框的显示与否及其内容
- 将一个函数配置为可取消的函数并显示一个取消按钮
- 配合qt-material等第三方库进行界面美化
- 添加菜单和工具栏
- 添加多个函数并显示函数选择界面
- 在函数中弹出对话框、输入框
- 在函数中向Output区域打印文字
- …
这些更高级的内容,如果后续有时间的话,将写一些文章单独讲讲,当然,也可以查看examples/ 示例代码,这些示例几乎涵盖了上面列举的全部主题。
最后,如果你喜欢这个库的话,麻烦给个star,谢谢啦。后续,我会持续维护这个库,如果有什么改进的建议,也欢迎通过issue的方式提出。
关于Python学习指南
学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后给大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!
包括:Python激活码+安装包、Python web开发,Python爬虫,Python数据分析,人工智能、自动化办公等学习教程。带你从零基础系统性的学好Python!
👉Python所有方向的学习路线👈
Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。(全套教程文末领取)
👉Python学习视频600合集👈
观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。
温馨提示:篇幅有限,已打包文件夹,获取方式在:文末
👉Python70个实战练手案例&源码👈
光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
👉Python大厂面试资料👈
我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
👉Python副业兼职路线&方法👈
学好 Python 不论是就业还是做副业赚钱都不错,但要学会兼职接单还是要有一个学习规划。
👉 这份完整版的Python全套学习资料已经上传,朋友们如果需要可以扫描下方CSDN官方认证二维码免费领取【保证100%免费
】