基于pywebview的桌面小工具开发记录

近期工作上有一个新的需求:开发一个桌面端小工具,用来将用户端数据按照标准协议转换并输出。工作以来,B/S项目是主要工作内容,其他的基于console的工具、手机端app也有一些,但是GUI的开发还是首次。

1. 技术选型

因为前段时间用pandas做了一些数据处理,非常欣赏pandas这种数据处理、数据分析的能力,思考了下项目中对excel的处理转换pandas都可以满足,所以打算基于python来完成这个小项目。python的GUI技术/框架非常多,可以参考GUI Programming in Python.

1. 原生GUI框架

最开始考虑使用原生GUI,于是基于google做了一些初步的调研分析:

GUI技术 优点 缺点
TKinter 原生,安装包小,性能好 容易上手,界面美化困难,代码结构不好,组件少,功能少,只适合极简的小工具
PyQT5 技术成熟,功能强大,多平台通用,界面精美 复杂度高,学习成本高,商业付费,打包后程序几百兆
PyGtk 跟PyQt一样,可以实现很不错的效果,但是稍逊于PyQt,并且同样有UI设计工具Glade 更适合GNOME平台
wxPython 免费开源,提供了设计器,复杂度比PyQT5低,能力比TK强 设计器不够强大,复杂界面不适合,界面美观度不够,跨平台可能需要调试
PySimpleGUI 基于Tkinter、Remi、wxPython和PyQt的封装,文档和示例丰富,封装了api,开发效率高,适合短平快项目 封装屏蔽了底层技术的实现细节,组件在各个底层技术上不全部通用

因为这个项目是一整套商业化平台的配套工具,许可问题放弃PyQT5;同时因为终端要支持mac和windows,PyGtk不适合;放弃TK是因为它的组件和功能满足不了项目需求;剩下的wxPython或者PySimpleGUI大致是比较接近需求的方案,不过上面列出的缺点也是让我有些顾虑。

2. 基于web的GUI实现

原生GUI框架避免不了的问题就是增加了额外的学习成本,Python的GUI实现也有一些基于web的实现框架,web的界面操作能力和开发效率都不是原生GUI能比的,如果能用web来解决需求,那当然是最合适的。初步调查结果如下:

技术 优点 缺点
EEL 非常轻量级,托管本地web服务器,实现python的js的互相调用 不原生支持flask等,需要系统提前安装chrome;打包后文件大;右键菜单不能禁用;
QWebview - 基于QT,许可问题
flaskwebgui 支持flask、fastapi、django等框架 依赖chrome,活跃度低不够成熟
PyWebview 轻量级,基于系统自带浏览器,启动速度快,支持flask 框架开放的接口有限,多平台打包需要调试
electron 基于nodejs,开发效率高,跨平台,vscode高山仰止 体积和内存占用比较大,不支持xp,部分api非全平台兼容,效率不如原生

调研过程中,被electron种草,不过最终决定不改初衷,这个项目还是使用ython+PyWebview实现;但是如果pywebview在使用中遇到比较严重的坑,也做好了随时切换到nodejs+electron的心理准备;中间也曾想过,使用python+nodejs+electron来实现,这样就兼顾到了electron和pandas,不过这样做毕竟不太优雅,为了把nodejs和python黏合到一起,同时运行了两套运行时,和一个额外的socket服务,不是第一选择。

2. 开发

pywebview支持两种方式集成html/js/css,一种是使用简易的内置的web服务器,一种是使用第三方的web框架,比如flask。因为内置web服务器局限性比较大也不够灵活,项目基于flask搭建。前端UI框架因为考虑到兼容IE使用了layui;数据处理使用pandas;项目打包使用pyinstaller

项目部分结构如下:

image.png
  1. biz:python主体逻辑部分
    • biz/App.py: flask应用构建和路由
    • biz/Configs.py: 项目配置,包括环境参数、窗口参数、日志等
    • biz/JsAPI.py: python数据处理类,暴露给前端js直接调用
    • biz/WebAPI.py: flask每条路由的处理方法类,前端可以通过ajax请求路由实现调用python的全部能力,加载web页面时候使用此方法可以向前端传递一些必要参数
    • biz/WindowHandler.py: 处理window窗口事件,如on_closed、on_loaded
  2. static: 放置项目用到的js、css、imgs
  3. templates: 放html页面及组件
  4. main_mac.pymain_win.py: 项目入口,因为配置不一样区分系统
  5. build.shbuild.bat: Pyinstaller脚本,打包app/exe
1) 使用virtualenv精简打包依赖,给安装包瘦身
2)webapi方法举例,加载首页时执行的方法:
    def root(self):
    """
    渲染 index.html
    """
    logger.info('root', 'token:', webview.token)
    width=config.get_config('window.width') 
    zoom=config.get_config('window.zoom')

    return render_template('index.html', token=webview.token,width=width,zoom=zoom ,context={"name": "my_app"})
3) jsapi方法举例:
def select_out_folder(self):
    """
    选择文件夹
    """
    return self._window.create_file_dialog(webview.FOLDER_DIALOG)

3. pywebview打包

image.png

pyinstaller打包在mac上基本上比较顺利,但是在windows上出现了一些问题,记录如下:

1) 打包脚本

pyinstaller打包windows exe时,相比mac上的脚本需要引入WebBrowserInterop.x64.dll,脚本如下:

pyinstaller  src/main_win.py -F -w -y ^
        --paths "src" ^
        --name="my_app" ^
        --add-data="venv/lib/site-packages/webview/lib/WebBrowserInterop.x64.dll;webview/lib" ^
        --add-data="src/static;static" ^
        --add-data="src/templates;templates" ^
        --add-data="src/log;log" ^
        --icon="icon.ico" ^
        --clean
2) clrModule.PyInit_clr()异常
image.png

因为mac上基于python3.9开发,所以在windows上搭建了同样的环境;但是pythonnet不支持python3.9导致该问题;将python降级到3.8,问题解决。

3)ERROR:icu_util.cc(133)] Invalid file descriptor to ICU data received.

在windows平台将gui=cef修改成mshtml;考虑到兼容性和客户端的多样性,windows安装包使用mshtml是最保险的。

4) 在windows平台上使用js调用JsAPI方法时,语法报错

IE11不支持promise语法,引入blurbird.js,修改原api中promise的实现方式,具体如下:

// 原API的promise调用方式
js_api.select_excel_file().then(response => {

}).catch(err => {
    console.error(err)
})

// 基于blurbird.js实现方式
js_api.select_excel_file().then(response => {

},err => {
    console.error(err)
})
5) windows下窗口大小不包括标题栏、滚动条

打包时根据平台使用两份配置,windows窗口额外增加标题栏高度和滚动条宽度

6)在windows平台,当html使用了scale缩放后,窗口在debug模式和非debug模式大小不一致

该问题暂时通过配置特殊处理walk around

7)windows下点击关闭按钮,主进程卡死(not responding)

pywebview的一个bug,在mac平台,不执行window的on_closed事件,关闭窗口需要在on_closing事件中执行window.destroy();
但是在windows平台,在on_closing事件中执行window.destroy()会导致主进程卡死;windows平台只能在on_closed事件关闭窗口

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容