Electron Python界面开发(通过zerorpc)

Python 开发GUI要么太繁琐要么太丑,而前端技术恰巧是最适合做漂亮UI的。所以考虑将Python和前端技术结合,通过进程通信和前端框架交流,打包成一个完整的桌面APP。教程分成两种实现方式,一个是zerorpc进程通信一个是http通信。

这篇教程介绍zerorpc的方式,流程如下:

start | V+--------------------+| | start| electron +-------------> +------------------+| | sub process | || (browser) | | python server || | | || (all html/css/js) | | (business logic) || | zerorpc | || (node.js runtime, | <-----------> | (zeromq server) || zeromq client) | communication | || | | |+--------------------+ +------------------+

Electron基础

详情见官方文档:
https://electronjs.org/docs

如果你可以建一个网站,你就可以建一个桌面应用程序。 Electron 是一个使用 JavaScript, HTML 和 CSS 等 Web 技术创建原生程序的框架,它负责比较难搞的部分,你只需把精力放在你的应用的核心上即可。

" />
" />

有很多有名的App是用Electeon开发的,如:Skype和GitHub以及著名编辑器Atom,所以这个框架在水平上是被认可的。

" />
" />

Electron 可以让你使用纯 JavaScript 调用丰富的原生(操作系统) APIs 来创造桌面应用。 你可以把它看作一个专注于桌面应用的 Node. js 的变体,而不是 Web 服务器。

这不意味着 Electron 是某个图形用户界面(GUI)库的 JavaScript 版本。 相反,Electron 使用 web 页面作为它的 GUI,所以你能把它看作成一个被 JavaScript 控制的,精简版的 Chromium 浏览器。

安装

为你的新Electron应用创建一个新的空文件夹。 打开你的命令行工具,然后从该文件夹运行npm init。将package.json修改一下。

{    'name': 'your-app',    'version': '0.1.0',    'main': 'main.js',    'scripts': {      'start': 'electron .'    } }

现在,您需要安装electron。 我们推荐的安装方法是把它作为您 app 中的开发依赖项,这使您可以在不同的 app 中使用不同的 Electron 版本。 在您的app所在文件夹中运行下面的命令:

npm install --save-dev electron

使用

electron模块包含了Electron提供的所有API和功能,引入方法和普通Node.js模块一样:

const electron = require('electron')

electron 模块所提供的功能都是通过命名空间暴露出来的。 比如说: electron.app负责管理Electron 应用程序的生命周期, electron.BrowserWindow类负责创建窗口。 下面是一个简单的main.js文件,它将在应用程序准备就绪后打开一个窗口:

const {app, BrowserWindow} = require('electron') function createWindow () { // 创建浏览器窗口 win = new BrowserWindow({width: 800, height: 600}) // 然后加载应用的 index.html。 win.loadFile('index.html') } app.on('ready', createWindow)

您应当在 main.js 中创建窗口,并处理程序中可能遇到的所有系统事件。 下面我们将完善上述例子,添加以下功能:打开开发者工具、处理窗口关闭事件、在macOS用户点击dock上图标时重建窗口,添加后,main. js 就像下面这样:

const {app, BrowserWindow} = require('electron')  // Keep a global reference of the window object, if you don't, the window will   // be closed automatically when the JavaScript object is garbage collected.   let win  function createWindow () {    // 创建浏览器窗口。     win = new BrowserWindow({width: 800, height: 600})    // 然后加载应用的 index.html。     win.loadFile('index.html')    // 打开开发者工具     win.webContents.openDevTools()    // 当 window 被关闭,这个事件会被触发。     win.on('closed', () => {      // 取消引用 window 对象,如果你的应用支持多窗口的话,       // 通常会把多个 window 对象存放在一个数组里面,       // 与此同时,你应该删除相应的元素。       win = null    })  }  // Electron 会在初始化后并准备   // 创建浏览器窗口时,调用这个函数。   // 部分 API 在 ready 事件触发后才能使用。   app.on('ready', createWindow)  // 当全部窗口关闭时退出。   app.on('window-all-closed', () => {    // 在 macOS 上,除非用户用 Cmd + Q 确定地退出,     // 否则绝大部分应用及其菜单栏会保持激活。     if (process.platform !== 'darwin') {      app.quit()    }  })  app.on('activate', () => {    // 在macOS上,当单击dock图标并且没有其他窗口打开时,     // 通常在应用程序中重新创建一个窗口。     if (win === null) {      createWindow()    }  })  // 在这个文件中,你可以续写应用剩下主进程代码。   // 也可以拆分成几个文件,然后用 require 导入。 

最后,创建你想展示的 index.html

<!DOCTYPE html> <html> <head> <meta charset='UTF-8'> <title>Hello World!</title> </head> <body> <h1>Hello World!</h1> We are using node <script>document.write(process.versions.node)</script>, Chrome <script>document.write(process.versions.chrome)</script>, and Electron <script>document.write(process.versions.electron)</script>. </body> </html>

启动

在创建并初始化完成 main.jsindex.htmlpackage.json之后,您就可以在当前工程的根目录执行 npm start 命令来启动刚刚编写好的Electron程序了。

" />
" />

Python部分

安装pip install zerorpc。在项目根目录创建文件夹py,用于存放Python相关代码。新建一个python文件,命名为api.py。敲入如下demo。

import zerorpcclass HelloRPC(object):    def hello(self, name):        return 'Hello, %s' % names = zerorpc.Server(HelloRPC())s.bind('tcp://0.0.0.0:4242')s.run()

然后命令行里运行python api.py。再另一个终端输入zerorpc tcp://localhost:4242 hello NXB,如果得到Hello,NXB则没有问题。

Electron部分

接着之前的main.js后面写。我们首先需要node.js能够调用Python进程。

const path=require('path')let pyProc = nulllet pyPort = nullconst createPyProc = () => { let port = '4242' let script = path.join(__dirname, 'py', 'api.py') pyProc = require('child_process').spawn('python', [script, port]) if (pyProc != null) { console.log('child process success') }}const exitPyProc = () => { pyProc.kill() pyProc = null pyPort = null}app.on('ready', createPyProc)app.on('will-quit', exitPyProc)

写完后运行npm start看看能不能启动python子程序按照之前的方式测试一下能不能通信。没问题的话继续。

修改我们的主页index.html,构建一个输入框。我们希望在输入框里输入字符,下方可以动态显示Hello,XX。

<!-- index.html --><!DOCTYPE html><html>  <head>    <meta charset='UTF-8'>    <title>Hello XX</title>  </head>  <body>    <input id='name' ></input>    <p id='result' color='black'></p>  </body>  <script>    require('./render.js')  </script></html>

在根目录下创建render.js用于监听输入框,将输入框的内容动态发送给python进程,并接收反回来的消息。

// renderer.js var zerorpc = require('zerorpc');var client = new zerorpc.Client();client.connect('tcp://127.0.0.1:4242');let name = document.querySelector('#name')let result = document.querySelector('#result')name.addEventListener('input', () => { client.invoke('hello', name.value, (error, res) => { if(error) { console.error(error) } else { result.textContent = res } })})name.dispatchEvent(new Event('input'))

如果没问题的话应该是这样的效果:

" />

打包

测试没问题之后我们需要将应用打包,因为别人电脑上不一定装了node.js或是python。首先要装个打包工具pip install pyinstaller

package.jsonscript中加入'build-python':'pyinstaller ./py/api.py --clean --distpath ./pydist'。然后运行npm run build-python编译一下。编译完了可以把根目录下生成的build文件夹和api.spec删了。如果中间报错 AttributeError: module 'enum' has no attribute 'IntFlag',就运行pip uninstall enum34把enum34删了。

This is likely caused by the package
enum34. Since python 3.4 there’s a standard library
enummodule, so you should uninstall
enum34, which is no longer compatible with the enum in the standard library since
enum.IntFlag was added in python 3.6

之前子进程是通过调用python命令运行的,现在我们要换成生成的可执行程序。修改main.js

// let script = path.join(__dirname, 'py', 'api.py')   // pyProc = require('child_process').spawn('python', [script, port])   let script = path.join(__dirname, 'pydist', 'api','api')  pyProc = require('child_process').execFile(script, [port])

运行npm start可以查看效果。

在根目录运行npm install electron-packager --save-dev安装Electron打包模块。然后将'pack-app': './node_modules/.bin/electron-packager . --overwrite --ignore=py$'写入package.json的script中。

运行npm run pack-app打包程序。最后会生成可执行文件,复制到别的电脑也可以运行。

" />
" />

nofacer/Python_GUI_with_Electron​ github.com

" />

(0)

相关推荐