[Python]使用Eel使用HTML / CSS / JavaScript构建GUI


介绍

  • 我想用Python制作一个GUI应用程序。
  • 我尝试了Tkinter和Kivi,但是尝试创建精细的布局却感到沮丧。
  • 我想使用HTML / CSS / JavaScript WEB技术创建GUI。但是,使用电子很重。

Eel是用于这种情况的完美Python GUI库。
Eel是一个非常简单的类似于电子的GUI库,可以很容易地构建一个将Python(擅长于Numpy和Pandas等数据处理)与JavaScript(擅长于绘制D3.js等图形)的应用程序连接的应用程序。

下面,我将根据官方GitHub的自述文件进行解释。

  • 执行环境

    • Windows 10
    • Python3.6
    • 鳗鱼0.9.7

安装

让我们

pip install eel

你好世界

根目录中创建main.py并将WEB相关文件放置在web目录下。

1
2
3
4
5
main.py
web/
  main.html
  css/
  js/

仅用3行编写脚本,

main.py

1
2
3
import eel
eel.init("web")
eel.start("main.html")

如果编写适当的HTML并执行python main.py

main.html

1
2
3
4
5
6
7
8
9
<html>
<head>
    <meta charset="UTF-8">
    Eel
</head>
<body>
    Hello World!!
</body>
</html>

这样就完成了Hello World。
hello.png

从Python调用JavaScript函数

读取

eel.jseel.expose(js_function)后,您要从Python调用的函数。

main.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<html>
<head>
    <meta charset="UTF-8">
    Eel
</head>
<body>
    <div id="target"></div>
    <script type="text/javascript" src="/eel.js"></script>
    <script type="text/javascript">
        eel.expose(js_function)
        function js_function(values) {
            var s = ""
            for (var i = 0; i < values.length; i++) { s += values[i] + "<br>" }
            document.getElementById("target").innerHTML = s
        }
    </script>
</body>
</html>

您可以使用

eel.js_function()调用expose JavaScript函数。

main.py

1
2
3
4
5
6
import eel
import numpy as np

eel.init("web")
eel.js_function(np.random.rand(4).tolist()) # JSON serializableでないとダメ
eel.start("main.html")

获取Python

中JavaScript函数的返回值

有两种方法可以获取Python中JavaScript函数的返回值:回调和等待同步。

设置回叫

一种方法是设置一个回调函数,该函数将在JavaScript函数完成后执行。

1
2
3
4
eel.expose(js_function);
function js_function(args) {
  return "hogehoge";
}
1
eel.js_function(args)(lambda val: print(val + " from JavaScript"))

等待同步

另一种方法是放置空括号并等待JavaScript函数完成。如果在eel.start()之前调用它,它将冻结。

1
val = eel.js_function(args)()

从JavaScript调用Python函数

@eel.expose装饰要从JavaScript调用的Python函数。

main.py

1
2
3
4
5
6
7
8
import eel

@eel.expose
def python_function(val):
    print(val + " from JavaScript")

eel.init("web")
eel.start("main.html")

阅读

eel.js之后,可以使用eel.python_function(args)调用Python函数。
JavaScript数组将转换为Python list,而关联数组将转换为dict

main.html

1
2
3
4
5
6
7
8
9
10
11
12
<html>
<head>
    <meta charset="UTF-8">
    Eel
</head>
<body>
    <script type="text/javascript" src="/eel.js"></script>
    <script type="text/javascript">
        eel.python_function("aa")
    </script>
</body>
</html>

获取JavaScript

中Python函数的返回值

使用

async await

1
2
3
@eel.expose
def python_function2():
    return "Hello"
1
2
3
4
5
async function run() {
    let val = await eel.python_function2()();
    console.log(val + " from Python")
}
run();

启动时的选项设置

1
2
3
4
5
6
7
8
9
10
11
web_app_options = {
    "mode": "chrome-app",  # chromeのアプリケーションモードで起動
                           # "chrome" とすると、通常のchromeで起動
    "port": 8080,
    "chromeFlags": [
            "--start-fullscreen",  # フルスクリーンで起動 他のChromeが起動していると機能しない?
            # "--window-size=800,600",
            # "--window-position=0,0",
    ]
}
eel.start("main.html", options=web_app_options)

多线程

您可以使用

eel.sleep()eel.spawn()轻松地使其成为多线程。下面的示例是

  • 托管Web服务器的线程
  • my_other_thread
  • 主螺纹

它是一个运行

中的3的脚本。

1
2
3
4
5
6
7
8
9
10
11
import eel
eel.init("web")
def my_other_thread():
    while True:
        print("I'm a thread")
        eel.sleep(1.0) # time.sleep()でなくて、eel.sleep()を使うこと
eel.spawn(my_other_thread)
eel.start("main.html", block=False) # block=Falseとしないと、ここで止まってしまう
while True:
    print("I'm a main loop")
    eel.sleep(1.0)

操作样本(思慕雪实时图形)

在Python中,图形为matplotlib,但是在这里,让我们使用JavaScript库Smoothie Charts绘制实时图形。

main.py

1
2
3
4
5
6
7
8
9
10
11
12
13
import random
import time
import eel

eel.init("web")
web_app_options = {"chromeFlags": ["--window-size=420,200"]}
eel.start("main.html", options=web_app_options, block=False)

while True:
    eel.push_data([
        {"time": time.time() * 1000, "value": random.random()}, # JSのgetTime()と同じにするためミリ秒に直す
    ])
    eel.sleep(0.2)

main.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<html>
<head>
    <meta charset="UTF-8">
    Chart
</head>
<body>
    <div id="parent" style="height: 100%;">
        <canvas id="mycanvas"></canvas>
    </div>
    <script type="text/javascript" src="/eel.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/smoothie/1.34.0/smoothie.min.js"></script>
    <script type="text/javascript">
        // canvasの高さと幅を画面に合わせる
        var parent = document.getElementById("parent")
        var canvas = document.getElementById("mycanvas")
        canvas.width = parent.clientWidth
        canvas.height = parent.clientHeight

        var smoothie = new SmoothieChart();
        smoothie.streamTo(canvas);
        var series = new TimeSeries();
        smoothie.addTimeSeries(series);

        eel.expose(push_data)
        function push_data(values) {
            for (var i = 0; i < values.length; i++) {
                series.append(values[i]["time"], values[i]["value"]);
            }
        }
    </script>
</body>
</html>

chart.png

二元

  • 执行pip install pyinstaller并安装PyInstaller

  • main.py目录中运行python -m eel main.py web将使用所需参数运行PyInstaller

  • 然后,将在dist目录下创建可执行文件。
    • 您还可以将PyInstaller选项添加到参数

      • --onefile合并为一个文件

      • --noconsole隐藏控制台

      • --exclude [モジュール名]删除不必要导入的模块