WIN10 Electron+Python界面开发(通信方式:thrift)

WIN10 Electron+Python界面开发(通信方式:thrift)

​ Python做界面开发要么繁琐要么太丑,同时Python客户端开发人员又是非常稀少的。而WEB前端工程师一抓一大把,同时WEB前端所开发出来的界面及交互效果都是非常美观的,同时有的软件可能客户端也需要,WEB端也需要,甚至移动端也需要,在要求美观的同时,有没有一个解决方案就能适应所有平台的呢?

​ 没错,目前最好的解决方案就是做WEB开发,首先其本身能在WEB上使用,对于移动端来讲,打包WEBAPP的工具一搜一大堆,而想同时能满足客户端的需求? 那就可以使用Electron了。

Electron也已经比较成熟了,目前很多界面每隔的桌面程序都是Electron开发的,比如说:Github、Skype、Atom、VSCode等。

​ 而此篇博文主要分享Electron+Python的方式做界面开发。网上也有比较多的教程,但大部分教程里Electron和Python的通信方式要么是Http,要么是zerorpc,Http太笨重,且不太适合客户端程序;npm的zerorpc安装过程太繁琐,太多版本问题,反正我用npm安装zerorpc搞了好几天都没弄好,因此最终换其他通信方案(期间也试过谷歌的gRPC),比较后最终选择Thrift,除了性能优势外,安装及配置都比较简单。

​ 流程如下:

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

安装配置

  • 系统:win10

  • 开发环境:

    • Python: 3.7
    • node: v10.15.3
    • npm: 6.9.0
  • python环境:

    • pip install thrift
  • 步骤:

    1. 首先创建你的应用文件夹: app

    2. 进入文件夹 npm init 初始化

    3. 修改package.json文件,参考:

      {
        "name": "ele_test",
        "version": "1.0.0",
        "description": "",
        "main": "main.js",
        "dependencies": {
          "thrift": "^0.12.0"
        },
        "devDependencies": {},
        "scripts": {
          "start": "electron ."
        },
        "author": "",
        "license": "ISC"
      }
      
    4. 安装npm第三方包:

      • npm install electron -g(如果安装太慢或者安装不了的话试试先安装cnpm,再使用cnpm install electron -g)
      • npm install thrift
    5. 去github下载thrift.exe(其他平台下载相应内容即可)

    6. 新建接口文件test.thrift:

      service userService {
          string test1(1:string name)
      }
      
    7. 生成各自的接口文件:

      thrift -out 存储路径 --gen 接口语言 thrift接口文件名

开发

编写客户端(前端)相关文件:

在app目录下新建文件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, webPreferences:{nodeIntegration:true}})

    // 然后加载应用的 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 导入。

  const path=require('path')

let pyProc = null
let pyPort = null


const createPyProc = () => {
  // let port = '4242'
  let script = path.join(__dirname, 'py', 'thrift_server.py')
  pyProc = require('child_process').spawn('python', [script])
  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)

新建文件render.js:

// renderer.js
var thrift = require('thrift');
// 调用win10下thrift命令自动生成的依赖包
var userService = require('./gen-nodejs/userService.js');
var ttypes = require('./gen-nodejs/test_types.js');
var thriftConnection = thrift.createConnection('127.0.0.1', 8000);
var thriftClient = thrift.createClient(userService,thriftConnection);

thriftConnection.on("error",function(e)
{
    console.log(e);
});


/* 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', () => {
  var dic = {name: name.value}
  dic = JSON.stringify(dic)
  thriftClient.test1(dic, (error, res) => {
    if(error) {
      console.error(error)
    } else {
      result.textContent = res
    }
  })
})
name.dispatchEvent(new Event('input'))

新建index.html:

<!-- 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')
    // import './render.js'
  </script>
</html>
编写服务端相关文件

在app目录下新建目录py,

进入py目录,新建文件thrift_server.py:

import json
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.server import TServer

from gen_py.test import userService


class Test:
    def test1(self, dic):
        print("one")
        dic = json.loads(dic)
        return f'Hello, {dic["name"]}!'


if __name__ == "__main__":
    port = 8000
    ip = "127.0.0.1"
    # 创建服务端
    handler = Test()  # 自定义类
    processor = userService.Processor(handler)  # userService为python接口文件自动生成
    # 监听端口
    transport = TSocket.TServerSocket(ip, port)  # ip与port位置不可交换
    # 选择传输层
    tfactory = TTransport.TBufferedTransportFactory()
    # 选择传输协议
    pfactory = TBinaryProtocol.TBinaryProtocolFactory()
    # 创建服务端
    server = TServer.TThreadedServer(processor, transport, tfactory, pfactory)
    print("start server in python")
    server.serve()
    print("Done")

启动

运行npm start即可运行

打包

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

package.jsonscript中加入"build-python":"pyinstaller ./py/thrift_server.py --clean"。然后运行npm run build-python编译一下。编译完了可以把根目录下生成的build文件夹和thrift_server.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', 'thrift_server.py')
  // pyProc = require('child_process').spawn('python', [script])
  let script = path.join(__dirname, 'py', 'dist','thrift_server')
  pyProc = require('child_process').execFile(script)

运行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打包程序。最后会生成可执行文件,复制到别的电脑也可以运行。

代码已上传至Github

  • 13
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 22
    评论
要实现 ElectronPython 后端的通信,并将它们打包成一个应用程序,你可以按照以下步骤进行操作: 1. 通过子进程通信:在 Electron 的主进程中,使用 Node.js 的 `child_process` 模块与 Python 后端进行通信,如前面所述。确保你的 Python 后端可以接收来自 Electron 的输入,并发送输出。 2. 设计通信协议:定义 ElectronPython 之间的通信协议,包括数据格式和消息传递的方式。可以使用 JSON 作为数据格式,约定好消息的结构和字段。 3. 封装通信逻辑:在 Electron 的主进程中,编写逻辑代码来处理与 Python 后端的通信。例如,可以封装一个函数,用于发送消息给 Python,并监听 Python 返回的消息。 4. 打包应用程序:使用 Electron 提供的打包工具将 ElectronPython 后端打包成一个应用程序。你可以使用工具如 `electron-builder` 或 `electron-packager` 来打包 Electron 应用程序,并将 Python 后端代码一同打包进去。 5. 部署应用程序:将打包好的应用程序部署到目标平台上。根据目标平台的要求,你可以生成适应不同操作系统的安装包或可执行文件。 需要注意的是,由于 Electron 是基于 Chromium 和 Node.js 的,它可以在客户端直接运行 Python 代码,而不需要依赖于一个单独的 Python 后端。如果你只是想在客户端运行 Python 脚本,而不需要与后端进行通信,可以考虑使用 `python-shell` 模块或 `pyodide`,它们提供了在 Electron 中运行 Python 代码的功能。这样可以简化通信的实现和打包的流程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值