如何用 Vue.js + Electron 把你的 Python 控制台应用套上好看的 GUI[0]
# 引言
通常,捉虫的程序员总是活跃在月黑风高的后半夜。漫漫长夜过后,看到项目里的虫子终于应捉尽捉,幸运的嵌入式/算法/测试程序员总算可以长舒一口气。
但黑洞洞的命令行对于行外人总是不那么友好,就像黑底白字总是不如图文并茂来的直观。命令行交互常常把我们的奇思妙想局限于一个很小圈子,供有限的 Geek 朋友自娱自乐。毕竟我们很难指望甲方爸爸会喜爱一个黑洞洞的命令行程序,或者凭几行代码向心仪的对象展示才华。
人靠衣裳马靠鞍。为我们的命令行工程套上壳有时十分必要。一个晦涩但是功能强大的脚本就像一位掌握高深技术的专家,而一个 GUI(Graphical User Interface,图形用户界面)可以帮助专家变得更容易沟通,以便向世界分享他的价值。对一个面向企业的商业项目来说,一个能用的 GUI 一般就可以交差了。但一个闲着没事有理想的程序员显然不会止步于此。既然决定为项目套壳,不妨更进一步,去做一个好看的壳。一个好看的 GUI 像是干练的专家套上体面的行头,即使你一辈子也不愿意了解他的技术,但就是没办法讨厌他。
由于平时工作的原因,经常会接触到嵌入式编程和算法实现,常用的语言是C
/C++
和Python
。有时候在嵌入式设备上实现的功能需要使用上位机来控制和展示,比如发送命令、接收数据、绘图展示。一些算法效果也需要绘图画表来表现。这种需求平时都是用 Python
来实现的。Python
的 matplotlib
库和 Pandas
库可以完成绝大部分绘图画表工作,Python
的 pyserial
库也可以通过串口完成与嵌入式设备的交互。更进一步的,GUI 部分一般使用 Python
自带的 tkinter
来完成。可以说 Python
最为一种众所周知的简单又强大的语言,可以胜任几乎所有我目前接触到的工作。但看着 tkinter
上仿佛上世纪穿越过来的 UI 风格,或者你也曾经调参->编译->调参->编译...地调试过元件位置,可能你也会产生和我一样的向往:用一种优雅的工具制作优雅的 GUI。
可惜梦想总是丰满的。利用在家摸鱼在家工作的宝贵闲暇,我凭借着几乎为零的 JavaScript 基础和从初中二年级带来的网页开发经验,瞎搞胡搞了两个星期,总算是做出了一个还算看得过去的应用。写这些东西,也是希望给那些有和我一样美好愿望又涉世未深的朋友们做出一点微小的贡献。
我做的应用大概就是这个样子的 👇
# 技术调研
在真正上手之前,先做一个简单的技术调研。因为时间有限又疏于整理,所以这一部分难免片面、肤浅、充满幻想或经验主义(其实就是偏见)。希望以后可以再补充完善。
# 基本情况
比较主流的 GUI 工具大体有:基于 C++
的 Qt
,基于 Python
的 Tkinter
、pyQt
, MATLAB
自带的 GUI 工具箱,基于 Node.js
的 electron
。前三种都是比较传统的工具,是我平时可以见得到的;后者于我而言新意虽然已经不新了在于将制作网页的技术用于制作桌面应用的 GUI。其具体的实现又涉及到诸如 webpack
等许许多多我暂时也没搞明白的 WEB 工具。
最后我选了 electron
。除了本来就对网页编程充满好奇,还有一些其它的原因,下面简单说明。
# 我为什么没有选择 Qt
、Tkinter
、pyQt
和 MATLAB
的 GUI 工具箱
Qt
作为目前主流的跨平台 GUI 工具,个人理解算是 C++
的一种拓展,并提供了比较完善的 IDE。虽然Qt社区经过多年发展,已经有了很多宝贵的积累,但是对于我这样的初学者而言,所见的 Qt
项目大都称不上优雅。一是 UI 风格多半比较原始,二是用 C++
来做多线程编程总觉得过于复杂,之前没有尝试过,未来也暂时不想尝试。相比之下,基于 Python
的 GUI 工具在编程上对我来说稍微顺手一些。实际上,以前出于兴趣也对 Tkinter
和 pyQt
做了简单了解。由于没有像 Qt
那样完善的 IDE,Tkinter
和 pyQt
都是需要完全依靠程序脚本来设计样式、属性的。可以说这种噩梦一样的样式编程直接把我劝退了。除了这些方案,MATLAB
也提供了 GUI 工具箱。这个工具箱除了 UI 风格复古,最大的问题还是收费而且巨贵。
除了上面的原因,还有一个问题是,上面这些工具似乎对于不同分辨率的支持都不太好,或者说对于移动端的支持不太好。表现在串口在缩放时组件大小和组件布局的自动调整表现不佳。
总的来说,有些出于个人喜好的原因,也有些是工具不够容易上手的硬伤,最后我把希望寄托在基于 WEB 创建 GUI 应用上。
# 基于 WEB 的技术的优势
基于 WEB 创建 GUI 应用主要是因为 WEB 技术依靠 Chrome 内核提供了强大的跨平台通用性。由于基于 Chrome 内核的 node.js
在 Linux 和 Windows 乃至 Android 上都有实现,使得我们可以从围绕操作系统的底层编程上解放出来,从而专注于逻辑和界面的设计。就我粗浅的了解看来,一般仅仅需要做很少的改动就可以从一个平台迁移到另一平台,甚至发布为网页。
当然这只是一个小众的需求。我依然有这方面的执念,除了太闲,一部分原因在于在我有限的交付经历里,在这上面栽过跟头。起因是当时我们希望将 Python
脚本打包成 exe
可执行文件发布。本来软件在 Windows10 上运行妥妥的,结果在甲方的 Windows7 上出了问题。原因可能是因为用来做 GUI 的 Tkinter
调用了某个在 Windows7 上不兼容的链接库。说来惭愧,起初没有想到会出现这个问题,花了太多时间处理无关紧要的 bug。结果 ddl 将至赶着交付,不得不把客户的系统强行升级成了 Windows10。我的直觉告诉我: WEB 应用的跨平台通用性可以让我不幸再次遭遇类似情况时,至少可以把 GUI 剥离出来变成网页,以暴露一部分源码为代价获得通用性。只要核心逻辑还可以打包应该就问题不大。
另一方面,WEB 技术已经相当强大。浏览器天然的多线程特性适合处理上位机 - 下位机通信的场景。系统级的操作也有丰富的 API 支持。
在上手难度上,node.js
背后也有着丰富的文档和活跃的社区支撑。前端技术的成熟孕育了活跃的开源社区,使得各种各样优美的页面方案触手可及。浏览器就是天然的调试器:页面的设计所见即所得,所有的更改都马上得到反馈;调试逻辑时也随时可以设置断点。
# 做出了一个什么东西
因为最近正好在学习卡尔曼滤波算法,就这借着这个机会做了一个演示算法的 demo。具体来说,是一个 Windows 平台的应用程序,允许用户修改一些参数,如: 输入信号 、基准滤波器(滑动平均)的 滤波器阶数 以及卡尔曼滤波器的有关参数,然后展示卡尔曼滤波的效果。展示效果的部分用到了交互式图表。
这个 demo 的结构是:以 Electron
创建的应用程序为入口,前端基于 Vue
设计 GUI 页面,同时运行一个 Python
子进程作为后端。在前端使用 chart.js
绘制图表,使用原生的 WebSocket
创建客户端(Client)与 Python
子进程通信。GUI 上用户的输入、WebSocket
收发的消息以及图表依赖的数据都直接存储在 Vuex
生成的存储单元中并相互分享。后端负责较复杂的专业计算和逻辑,特别是矩阵运算由 Numpy
实现,同时使用 Flask-sockets
创建 WebSocket
服务端(Server)。前后端通过虚拟的网口连接后,前端将用户输入的数据发送给后端,后端进行相应的处理后将相关的数据回复给前端,前端将其汇总为图表显示给用户。
这一部分做为一个引子。具体如何实现这个应用,将在后面详细介绍。