Python + Flask + Electron 混合开发入门 (项目演示)

写在前面

注: 如果您是第二次阅读本文, 推荐直接阅读 快速开始 章节以快速复现最终运行效果.

本文所涉及文件已存放在网盘空间: https://www.jianguoyun.com/p/DdlvwhwQ7t6sBxjJkcoB 欢迎下载使用.

概述

本文是基于一个 python 开发者的角度, 尝试使用 electron 来开发桌面应用.

请注意本文只是一个面向新手的文章. 内容涉及 如何让 electron 调用起 python 模块, 以及 python 的数据如何传递到 electron 界面展示出来.

背景

本文假设读者已具备以下能力:

  1. 有一定的 python 基础
  2. 有少量的 javascript 知识 (能够写出 hello world 的程度)
  3. 会用 npm init 初始化项目
  4. 完成过 electron 的 hello world 类项目的启动

本文假设读者已经做好以下准备:

  1. 安装 nodejs, npm, python 3
    1. 安装模块 (推荐安装在测试项目目录下):
      1. nodejs 模块: electron, python-shell
      2. python 模块: flask
  2. 编辑器. vscode, pycharm, webstorm 都可以
  3. 创建本次测试项目的目录, 比如我的项目路径为 “D:/workspace/test_room/electron_with_python/”, 后面将简称为 “electron_with_python” 或者 “本项目”

正文

1. 初始化项目

通过 npm init 初始化项目. 得到的项目目录结构如下:

D:/workspace/test_room/electron_with_python/
	node_modules/  # 这是 npm 在本项目的模块安装目录
	venv/  # 这是 python 在本项目的虚拟环境 (包含编译器, 本项目安装的模块等)
	index.html
	main.js
	package.json

然后在本项目中通过 npm installpip install 来安装 electron, python-shell, flask 模块.

index.html, main.js, package.json 的源码见下面. 我尽量在保持易于阅读的基础上最简化 (注: 并非最终代码), 代码如下:

index.html

<h1>Welcome</h1>
<h3>This is a python-electron app.</h3>

main.js

// 导入模块
const { app, BrowserWindow } = require("electron")

// 创建窗口
function createWindow() {
    let win = new BrowserWindow({
        // 设置一个宽为800, 高为600的窗口
        width: 800,
        height: 600
    })
    // 加载本地的 index.html
    win.loadFile("index.html")
}

// 启动
app.on("ready", createWindow)

package.json (注意 devDependencies 中要有 electron 和 python-shell 两个模块)

{
  "name": "electron_with_python",
  "version": "1.0.0",
  "description": "Python + Flask + Electron 项目演示",
  "main": "main.js",
  "scripts": {
    "start": "electron ."
  },
  "author": "Likianta",
  "license": "ISC",
  "devDependencies": {
    "electron": "^4.1.3",
    "python-shell": "^1.0.7"
  }
}

在命令行 cd 到本项目路径, 输入 npm start 启动, 大家看到的效果应该和下图一样:

1554906638332.png

2. 加入 python-shell

python-shell 是一个 nodejs 模块, 所以可以在 main.js 中导入并使用.

python-shell 用于调用 python 写的 py 文件, 所以我们先在项目下新建一个 “hello.py” 文件:

# ./hello.py

# 里面就一句话
print("hello from python")

然后修改 main.js 文件:

const { app, BrowserWindow } = require("electron")

// 创建窗口
function createWindow() {
    let win = new BrowserWindow({
        width: 800,
        height: 600
    })
    win.loadFile("index.html")
}

// 从 python-shell 导入一个 PythonShell 对象 (注意大小写)
const {PythonShell}  = require("python-shell")
// PythonShell 主要有 run() 和 runString() 两个方法, 这里我们用 run()
// run() 第一个参数是要调用的 py 文件的路径
// 第二个参数是可选配置 (一般传 null)
// 第三个参数是回调函数
PythonShell.run(
	"hello.py", null, function (err, results) {
        if (err) throw err
        console.log('hello.py finished')
        console.log('results', results)
    }
)

// 启动
app.on("ready", createWindow)

启动效果如下, 可以看到 main.js 中的两条 console.log() 都被触发成功:

[外链图片转存失败(img-BBICF1p5-1563031004213)(https://i.loli.net/2019/04/11/5cae1716b40c2.png)]

这意味着到了这里, 我们已经实现了 electron 调用 python 模块的功能.

3. 加入 flask

大家对 flask 可能比较陌生, 目前只需知道它是一个 python web 框架 (微服务) 就可以了.

既然是 web 框架, 就肯定有端口, 路由, html 渲染模板等东西.

在项目下新建一个 engine.py, 代码如下:

from flask import Flask, render_template

'''
导入的这两个模块, Flask 是主体类, render_template 是渲染模板.
'''

# 首先创建一个变量 app, 用于初始化 flask 启动核心
app = Flask(__name__)
'''
感兴趣的可以看一下它的源码, 当我们把 __name__ 传进去后, Flask 的实例化行为:
    (flask 源码) app.py -> Flask.__init__()
        (flask 源码) helpers.py -> _PackageBoundObject.__init__()
可以看到, Flask 会根据你传的 __name__ 定位到程序 (engine.py) 所在的根路径.
这个根路径的用处和 render_template 有关. 后面会讲.
'''


@app.route('/')
def homepage():
    # 将本函数绑定到路由根地址, 这样我们访问主地址时, 就能看到这个页面
    home = 'flask_welcome.html'  # 还未创建, 接下来会写
    return render_template(home)


if __name__ == "__main__":
    # 启动, 启动后访问 http://127.0.0.1:5858 查看
    app.run(host='127.0.0.1', port=5858)

再在项目下创建一个 “flask_welcome.html” 文件, 代码如下:

<h1>Welcome to Flask</h1>
<h3>This is a homepage rendered by flask.</h3>

现在我们尝试直接运行这个 py 文件看看效果:

20190410230305.gif

不幸的是, 访问主页就报错了.

报错的原因在 pycharm 控制台可以看到, 显示 jinja2 没有找到模板文件:

1554908841182.png

(这也是我喜欢 python 的原因之一, 报错容易诊断, 定位错误源方便.)

jinja2 模块是 flask 默认使用的模板渲染引擎, 也就是 render_template(home) 这个函数, 之前我们还没有讲, 现在补充知识:

Flask 默认会在程序根目录下的 templates 文件夹寻找要渲染的模板文件, 所以这里传入的模板文件的路径应是相对于 templates 目录的.

因此解决方法有两种, 要么想办法让 Flask 类的 template_folder 成员不要用 “templates” 作为模板目录入口, 要么就创建一个 templates 目录, 把 “flask_welcome.html” 放到里面.

第一种方法用一个自定义类继承于 Flask, 就可以任你发挥了, 当然这里我只演示第二种方法.

现在我们确认一下目录结构应该如下面所示:

D:/workspace/test_room/electron_with_python/
	node_modules/
	templates/
		flask_welcome.py
	venv/
	engine.py
	hello.py
	index.html
	main.js
	package.json

重新运行 engine.py, 在浏览器访问 http://127.0.0.1:5858/, 当如下图所示:

[外链图片转存失败(img-IS3WOL2g-1563031004214)(https://i.loli.net/2019/04/11/5cae171deed22.png)]

4. python, flask, electron 混合与实现

现在我们有了前三步的基础, 终于可以融会贯通了.

将 main.js 中的 “index.html” 改为 “templates/flask_welcome.html”, 把 “hello.py” 改为调用 “engine.py”, 来看看效果如何吧:

// main.js

const { app, BrowserWindow } = require("electron")

// 创建窗口
function createWindow() {
    let win = new BrowserWindow({
        width: 800,
        height: 600
    })
    // 加载 "templates/flask_welcome.html"
    win.loadFile("templates/flask_welcome.html")
}

// 使用 python-shell 调用 engine.py
const {PythonShell}  = require("python-shell")
PythonShell.run(
	"engine.py", null, function (err, results) {
        if (err) throw err
        console.log('engine.py is running')
        console.log('results', results)
    }
)

// 启动
app.on("ready", createWindow)

[外链图片转存失败(img-dgAbTzHF-1563031004215)(https://i.loli.net/2019/04/11/5cae1720e1f0c.gif)]

以上就是 python + flask + electron 的项目演示.


快速开始

注: 本节内容适合二次阅读的读者快速复习和复现.

  1. 初始化项目

    1. 创建项目: “D:/workspace/test_room/electron_with_python/”

    2. 项目目录结构:

      D:/workspace/test_room/electron_with_python/
      	node_modules/
      	templates/
      		flask_welcome.py
      	venv/
      	engine.py
      	hello.py
      	index.html
      	main.js
      	package.json
      
    3. 安装模块:

      1. npm install … : electron, python-shell
      2. pip install … : flask
  2. 创建代码文件: 请从此网盘链接下载: https://www.jianguoyun.com/p/DdlvwhwQ7t6sBxjJkcoB
    下载此压缩包: “electron_with_python_20190411_000145.zip”
    (PS: 为保持压缩包体积, node_modules 和 venv 里的内容我都清空了.)

  3. 打开命令行, cd 到项目目录

  4. 输入 npm start, 运行本项目

  5. 效果应与下图一致:
    1554912444291.png


扩展阅读

TODO

注意事项

  1. electron 的调试器端口不可以和 flask 相同, 否则会报错

参考

  • 12
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
Electron 是一个基于 Node.js 和 Chromium 的桌面应用程序开发框架,可以使用 HTML、CSS 和 JavaScript 来构建跨平台的桌面应用程序。在本文中,我们将介绍如何使用 PythonFlask 结合 Electron 编写一个简单的桌面应用程序。 1. 安装 Electron 首先,我们需要安装 Electron。可以通过 npm 来安装它: ``` npm install electron --save-dev ``` 2. 创建 Electron 应用程序 接下来,我们需要创建一个基本的 Electron 应用程序。在项目根目录下创建一个名为 main.js 的文件,并添加以下代码: ``` const { app, BrowserWindow } = require('electron') const path = require('path') function createWindow() { const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true } }) win.loadFile('index.html') win.webContents.openDevTools() } app.whenReady().then(() => { createWindow() app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow() } }) }) app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit() } }) ``` 这段代码创建了一个基本的窗口,加载了一个名为 index.html 的文件,并打开了开发者工具。 3. 创建 Flask 应用程序 然后,我们需要创建一个 Flask 应用程序。在项目根目录下创建一个名为 server.py 的文件,并添加以下代码: ``` from flask import Flask, jsonify app = Flask(__name__) @app.route('/api') def api(): return jsonify({'message': 'Hello, World!'}) if __name__ == '__main__': app.run(debug=True) ``` 这段代码创建了一个简单的 Flask 应用程序,具有一个名为 /api 的路由,返回了一个 JSON 响应。 4. 集成 Flask 应用程序 现在,我们需要将 Flask 应用程序集成到 Electron 应用程序中。在 main.js 文件中添加以下代码: ``` const { app, BrowserWindow } = require('electron') const path = require('path') const { spawn } = require('child_process') let flaskProcess = null const flaskPath = path.join(__dirname, 'server.py') function createWindow() { const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true } }) win.loadFile('index.html') win.webContents.openDevTools() } app.whenReady().then(() => { flaskProcess = spawn('python', [flaskPath]) createWindow() app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow() } }) }) app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit() } }) app.on('before-quit', () => { flaskProcess.kill() }) ``` 这段代码启动了一个 Python 进程来运行 Flask 应用程序,并在应用程序关闭之前杀死该进程。 5. 发起请求 最后,我们需要在渲染进程中发起请求。在项目根目录下创建一个名为 index.html 的文件,并添加以下代码: ``` <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Hello, World!</title> </head> <body> <h1 id="message"></h1> <script> const { ipcRenderer } = require('electron') ipcRenderer.on('message', (event, message) => { document.getElementById('message').textContent = message }) fetch('http://localhost:5000/api') .then(response => response.json()) .then(data => { ipcRenderer.send('message', data.message) }) .catch(error => console.error(error)) </script> </body> </html> ``` 这段代码使用 IPC 通信来从 Python 进程接收消息,并使用 fetch API 发起一个请求来获取 Flask 应用程序的响应。 6. 运行应用程序 现在,我们可以通过运行以下命令来启动应用程序: ``` npm start ``` 这将同时启动 Electron 应用程序和 Flask 应用程序,并打开一个窗口,显示来自 Flask 应用程序的消息。 至此,我们已经成功地构建了一个使用 PythonFlaskElectron 框架的桌面应用程序。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值