使用 web 技術構建 python 的 GUI 界面
來自專欄 SyntaxError
一般來說,選擇用於應用程序的 GUI 工具箱會是一個棘手的事情,Python 也不例外。對於 Python 來說,可以選擇的工具箱種類繁多。就我所知道的而言,比較常用的就有 TkInter, wxPython, PyQT/PySide 等。我試過 TkInter 和 wxPython,對 QT 的 Python 實現(PyQT/PySide)也作了略微的了解。大致來說,TkInter 相當於一個可用的預設選擇,但功能不夠強大。wxPython 則有更豐富的組件,可以實現絕大多數的應用需求。但是在布局效率,可定製性以及交互方式上面並不出眾。
web 技術的優勢
如果論快速構建出一個體驗良好的 UI 系統的話,我想沒有什麼技術能和 web 技術相比了。Web 天生就是為交互而生,利用 javascript,可以比較方便的實現各種交互;用 css 語言進行 UI 布局,可以對 UI 進行精確調控,而且是可見的,相對於 wxPython 之類的盲調,效率高了許多;Web 前端技術的繁榮,催生了很多實用的框架和庫,藉助 vue.js 等類似的響應式前端框架,能夠把精力集中在模型的構建上。這一切都讓使用 web 技術構建 UI 界面變得高效。
所以這些天,我查閱了一些資料,對需要使用的技術進行了選型,最終形成了一套比較成熟的解決方案。
整體架構
在架構上吸收了 MPV 模式的思想,盡量減少不同層之間的依賴,實現低耦度。而 View-Level 則通過 Vue 的類 MVVM 框架進行渲染。
使用到的技術棧/庫:
- node.js: Electron, Vue.js, webpack, zerorpc, element-ui
- Python: zerorpc, peewee
在整個架構中,具體功能和邏輯均由 Python 實現;Node.js 的部分僅作為視圖層進行數據展示及交互控制。Python 將具體功能暴露為 API,並通過 RPC 方式與 Node.js 進行通訊。
Model:與資料庫通信,將資料庫記錄的數據抽象成 python 可以識別的對象。
Presenter:響應 View 的操作,並和 Model 進行交互,向 View 返回數據。Logic 是其中具體實現邏輯的部分(可視為一個整體)。
View:基於 Electron 實現,採用 Vue.js 作為響應式框架。
Presenter 和 View 之間的通信通過 zerorpc 實現。
所涉及到的技術的簡述:
Electron:
Electron是由Github開發,用HTML,CSS和JavaScript來構建跨平台桌面應用程序的一個開源庫。原名 Atom Shell,起初是作為構建Github上可編程的文本編輯器Atom的框架而被開發出來,後來看著很好用就開源了,並改名 Electron。目前它已成為開源開發者、初創企業和老牌公司常用的開發工具。
Atom Shell,Electron,Atom Shell,Electron…嗯,原子的殼就是電子,你說的真對。
Electron 使用 Cromium 的渲染引擎,提供了一套類似瀏覽器的渲染環境,同時實現了與桌面系統進行交互的一系列介面。簡單的講,它可以認為是這兩樣東西的組合:一個可以運行網頁的瀏覽器,以及一些可以通過網頁調用系統原生資源的介面——例如原生的菜單,對話框,消息提示等。相當於在利用網頁強大的交互功能的基礎上,擴展了網頁與原生桌面進行交互的能力。而交互方式的實現則主要是通過 web 技術完成的,只是在實現交互的過程中,調用了一些介面,所以如果你熟悉 web 技術,用 Electron 編寫應用對你來說不會顯得太陌生。
正因為如此,Electron 在使用上是比較零散的,沒有什麼結構——而它的文檔也是如此。一般來講,你需要搞清楚 BrowserWindow,主進程與渲染進程等基本的概念,以及主/渲染進程之間相互調用的方式。其它的內容/介面,在需要用到的時候查閱對應的文檔就可以了,由於內容之間沒有太多的依賴,學習成本相對不高。
Electron 的官方文檔。大部分內容已經被翻譯為中文。
Mac App Store 和 Windows Store 都已支持 Electron 編寫的應用。但 Electron 並不能夠用來編寫移動應用,未來也不會支持。
Vue.js:
Vue.js 是一套用於構建用戶界面的漸進式框架。它的核心是一個允許採用簡潔的模板語法來聲明式地將數據渲染進 DOM 的系統,並且實現了響應式的數據綁定。此外,它還有強大的路由功能和組件系統,能夠模塊化的構建用戶界面。Vue.js 是一個結構化的東西,不同內容之間存在較為緊密的依賴,因此你需要完整的學習整個結構,學習成本是比較高的。即便是引用別人的組件,也需要知道它的工作方式,不然遇到各種奇怪的問題,你不知道怎麼解決。
Vue.js 具有完整的中文官方文檔。
electron-vue:
基於 vue (基本上是它聽起來的樣子) 來構造 electron 應用程序的樣板代碼。該項目的目的,是為了要避免使用 vue 手動建立起 electron 應用程序。electron-vue 充分利用 vue-cli 作為腳手架工具,加上擁有 vue-loader 的 webpack、electron-packager 或是 electron-builder,以及一些最常用的插件,如vue-router、vuex等等。
electron-vue 也有完整的中文官方文檔。使用前一定要完整的閱讀整個官方文檔。
ElementUI:
餓了么出品的一個前端組件庫。擁有常見的互動式組件,每個組件都有豐富的設置選項。這樣你就擁有了強大多樣的交互方式。加上這是 web,你可以很方便的將這些組件定製化,精確的實現獨特的需求。
zerorpc:
基於 ZeroMQ 的高性能分部式 RPC 框架。RPC 即遠程過程調用協議。不同過程之間通過 TCP 的方式進行通信。zerorpc 在 Python 和 node.js 上都有實現,因此我們可以通過 zerorpc 在 Python 和 node.js 之間進行通信。
peewee:
一個輕量級的 ORM (Object Relational Mapping) 庫。可以將資料庫抽象成 Python 可以識別的對象。使用方法和 Django model 很類似。
一些討論
文件大小:
為了打包 Electron 的依賴環境,Electron 最終生成的 exe 文件包至少有 70M 左右,這些都是 Electron 相關的依賴。但在 PC 使用環境中,這並不是什麼問題,80M 並不是很大的數字,相對於當今的硬碟空間根本不算什麼。只有在存儲資源稀缺的場景,如嵌入式開發中,文件大小才是有必要考慮的因素。
另外,你可以使用 UPX 對 electron.exe 和 node.dll 進行壓縮,壓縮後,這兩個文件的大小之和從 69M 下降到 25M 以下。
兼容性:
最近發現一個兼容性問題,在 win 7 中使用非 Aero 主題(就是透明邊框主題)時,從 electron 應用切換到其它應用時,其它應用的部分界面可能不會刷新,也就是在其它應用上留有 electron 應用的殘影。
這個問題是 electron 的一個歷史 bug,一定程度上也是 win 7 的一個缺陷。在所有用 electron 編寫的應用中,例如 VS Code, Slack,都存在該問題。目前 electron 官方並無解決該 bug 的意圖,唯有切換到 Aero 主題。
https://github.com/electron/electron/issues/1821關於評論區一些討論的匯總:
這些天和評論區的一些人進行了一些爭論和討論,有些評論很有道理,到這裡做個總結。
架構的一些缺陷
1. 架構的結構比較複雜,導致調試起來比較困難。有很多時候通過報錯,並不能比較直觀的找到錯誤的根源。特別是初期搭建的時候,需要花費比較大的精力。因此,對於比較簡單的需求是很不經濟的。
我是形成了一套以後可以復用的通用方法,後期使用會很方便,但前期搭建確實很痛苦,有很多匪夷所思的坑需要你去踩。
再就是 zerorpc 這個庫,坑很多,又沒文檔,經常需要你去看源碼,比如 node 端的 client 對象只有 connect 方法沒有 disconnect 方法,不知是作者忘了還是什麼,得你看源碼自己實現。(其實也還好,就是得花時間)
2. 打包後體積大,佔用資源略高
體積大主要是 electron 的依賴體積大,這跟用了兩個語言其實沒太大關係,python 的依賴(排除 modules )的體積相對來說並不大。所以對於小型程序不合適。
使用了 node.js 和 python,導致有兩個運行時。這樣確實比 「只用 python」 佔用更多的資源,但主要是 electron 比較耗資源,不是多一個運行時少一個運行時的問題。
隨著計算機性能的提升,在性能不是瓶頸的情況下,這問題真的可以忽略不計。單純一個 GUI 界面真的耗不了多少資源。反應都是瞬間,用戶根本感覺不出來區別。
當然這些都得看你具體的應用場景了。至少在我們實驗室那比較老舊的電腦上是沒什麼問題的,因為本來資源佔用也不高。
我覺得如今電腦性能已經非常強大,相對來說大部分應用並沒那麼耗資源,因此相比於那一點點的性能提升,編碼效率、用戶體驗、跨平台等才是更值得考慮的。
其它
3. 為什麼不全部由 node.js 實現?多用一個 python 是不是多此一舉?
我們討論的是,怎麼給 python 加一個 GUI 界面,這是前提。比如有些行業,python 是比較通用的語言,而 js 估計只有搞過前端的才會用,這樣 js 就不適合作為邏輯層面的代碼,但作為 GUI 層的代碼是沒有問題的。總之就是看你自己的使用場景了。
4. 關於學習成本
如果你沒有任何前端基礎,當然學習成本是很高了,你得先學 HTML,CSS, javascript, 然後再了解 node.js ,最後你還要熟練掌握 Vue.js(或者其替代品)和一個組件庫。webpack 的使用也是需要較長時間熟悉或踩坑的。
然而也有很多本來就懂得一些前端知識的人,對於他們來說,可能新學一個 GUI 庫成本更高吧。
------
另:關於如何用 zerorpc 在 electron 和 python 之間通信的例子,可參考我翻譯的這篇文章,裡面附有英文鏈接。
白銀之魔女:使用 web 技術構建 python 的 GUI 界面這篇文章我早翻譯了放在專欄了,偏偏有人質疑我的動機,放在這裡避免口舌之爭。
動機:
之前在知乎搜索"用 Web 技術做 python GUI"的相關內容,卻沒有比較好的解決方法,後來無意看到這篇文章,本著跟大家分享的善意翻譯過來,並且把自己最終的架構也分享出來。這問題據我所知關注的人還不少,因此應該對一些人有所幫助。
一篇翻譯,描述了用 electron 作為 python GUI 的基本方法。
一篇文章,分享了自己搭建的比較完整的架構。
這個方法確實有諸多缺陷,如評論中「英雄哥」所說,但也肯定有它的適用場景。大家自己選擇就好。
使用 web 技術構建 python 的 GUI 界面
推薦閱讀:
※[Nuxt.js 系列] 踩坑分享篇
※做好了一個很簡單的前端驗證加上後端的跳轉
※【aux】使用油猴腳本改進sketch measure
※介紹一個導出CSS精靈圖動畫的AE腳本