Gooey是一个装饰器库,能将Python命令行程序自动转换为友好的GUI界面程序,实际底层使用的是wxPython实现的界面。
对于一些小工具的编写特别有帮助,无需手动编写GUI程序即可快速实现。
官网地址:https://github.com/chriskiehl/Gooey
安装
简单示例
这里通过编写一个小工具来演示。工具实现的功能是将某个文件夹下面所有图片找出来后压缩为一个zip文件,然后保存到某个目录下。
那么这个程序的输入是一个文件夹,输出为一个zip文件全路径。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import os
import zipfile
from pathlib import Path
from gooey import Gooey , GooeyParser
@Gooey ( program_name = '文件夹图片搜集器' , language = 'chinese' , encoding = 'utf-8' )
def main ():
parser = GooeyParser ( description = '将一个文件夹中所有图片打包成一个zip' )
parser . add_argument ( 'Dir' , help = '文件夹' , widget = 'DirChooser' )
parser . add_argument ( 'Output' , help = '输出文件名' , widget = 'FileSaver' )
args = parser . parse_args ()
def real_work ():
# 执行耗时操作
file_list = os . listdir ( args . Dir )
images = []
for file in file_list :
extension = Path ( file ) . suffix
if extension in [ '.png' , '.jpg' , '.jpeg' , '.gif' , '.svg' ]:
images . append ( os . path . join ( args . Dir , file ))
zip_path = f ' { args . Output } '
with zipfile . ZipFile ( zip_path , 'w' , zipfile . ZIP_DEFLATED ) as zipf :
for image_path in images :
zipf . write ( image_path , arcname = image_path . split ( os . sep )[ - 1 ])
print ( f '压缩成功到: { zip_path } ' )
real_work ()
if __name__ == '__main__' :
main ()
运行后的效果图
打包
通常我们需要将程序打包后分发出去,目前常见的打包工具有pyinsaller和nuitka。这里我使用pyinstaller来演示怎么打包。
使用虚拟环境
使用虚拟环境可以减少冗余依赖,强烈推荐。
1
2
3
4
5
6
7
8
python -m venv pack_env
cd pack_env
# Windows激活命令
Scripts\activate
# 安装最小依赖
pip install pyinstaller python-gooey six
# 安装你的程序依赖(示例)
pip install pandas==2.0.3 # 只安装必要依赖的指定版本
下载UPX压缩工具(关键步骤)
下载后解压到任意目录(建议路径不要包含中文或空格):
官网下载:https://github.com/upx/upx/releases
准备一个应用图标
下载一个icon格式的图标作为可执行程序的图标。文件名命名为icon.ico,放在python脚本同级目录。
打包命令
这个是我最后调试好的单文件打包命令:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
pyinstaller -F -w \
--upx-dir "D:\libs\upx-5.0.1-win64" \
--upx-exclude "python3.dll" \
--upx-exclude "vcruntime140.dll" \
--exclude-module numpy \
--exclude-module panda \
--exclude-module matplotlib \
--exclude-module pytz \
--exclude-module tkinter \
--add-data "D:\Python\Python313\Lib\site-packages\gooey;gooey" \
--add-data "D:\Python\Python313\Lib\site-packages/gooey/languages;gooey/languages" \
--hidden-import=encodings \
--hidden-import "logging" \
--hidden-import "traceback" \
--distpath ./dist \
--workpath ./build \
-i icon.ico \
gooey_zip_pictures.py
参数解释:
-F:生成单个可执行文件 -w:禁用控制台窗口(适合GUI程序) –upx-dir:指定UPX路径(体积压缩关键) –exclude-module:排除非必要模块 –add-data:添加Gooey的依赖资源文件 -i:设置exe图标(可选) 高级优化
还可以在生产的spec文件添加如下内容
1
2
3
4
5
exe = EXE(...,
strip=True, # 去除调试符号
upx=True, # 启用UPX
optimize=2 # Python优化级别
)
中文编码问题
在打包成单个可执行文件后,执行程序过程中发现界面一直卡住,实际的zip文件已经生成了。最后那句print打印语句报错了。
我把-w参数去掉后重新打包后,再次执行能看到控制台窗口的报错信息如下:
1
2
3
4
5
6
7
8
9
10
Exception in thread Thread-1 (_forward_stdout):
Traceback (most recent call last):
File "threading.py", line 1041, in _bootstrap_inner
File "threading.py", line 992, in run
File "gooey\gui\processor.py", line 70, in _forward_stdout
_progress = self._extract_progress(line)
File "gooey\gui\processor.py", line 84, in _extract_progress
find = partial(re.search, string=text.strip().decode(self.encoding))
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xcb in position 2: invalid continuation byte
网上查询了各种资料后,最终解决方案如下,在程序开头部分添加编码设置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import io
import os
import sys
import zipfile
from pathlib import Path
from gooey import Gooey , GooeyParser
# 设置全局UTF-8编码环境
os . environ [ "PYTHONUTF8" ] = "1"
# 处理 sys.stdout 为 None 的情况
if sys . stdout is None :
# 禁用控制台时,输出重定向到空设备(避免错误)
sys . stdout = open ( os . devnull , 'w' , encoding = 'utf-8' )
elif sys . stdout . encoding != 'UTF-8' :
sys . stdout = io . TextIOWrapper ( sys . stdout . buffer , encoding = 'utf-8' )
@Gooey ( program_name = '文件夹图片搜集器' , language = 'chinese' , encoding = 'utf-8' )
def main ():
parser = GooeyParser ( description = '将一个文件夹中所有图片打包成一个zip' )
parser . add_argument ( 'Dir' , help = '文件夹' , widget = 'DirChooser' )
parser . add_argument ( 'Output' , help = '输出文件名' , widget = 'FileSaver' )
args = parser . parse_args ()
def real_work ():
# 执行耗时操作
file_list = os . listdir ( args . Dir )
images = []
for file in file_list :
extension = Path ( file ) . suffix
if extension in [ '.png' , '.jpg' , '.jpeg' , '.gif' , '.svg' ]:
images . append ( os . path . join ( args . Dir , file ))
zip_path = f ' { args . Output } '
with zipfile . ZipFile ( zip_path , 'w' , zipfile . ZIP_DEFLATED ) as zipf :
for image_path in images :
zipf . write ( image_path , arcname = image_path . split ( os . sep )[ - 1 ])
print ( f '压缩成功到: { zip_path } ' )
real_work ()
if __name__ == '__main__' :
main ()
高级控件
Gooey内置了很多GUI的控件,包括文本输入、密码输入框、下拉列表、CheckBox、颜色选择器、进度条等等。
还有自定义布局管理器可以按需定制界面布局效果。有兴趣的可以参考官网文档一个个去试。基本上已经能满足常见的使用了,这里就不演示了。