项目备份
This commit is contained in:
111
templates/app_JsToPy.html
Normal file
111
templates/app_JsToPy.html
Normal file
@@ -0,0 +1,111 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>PyWebView 双向通信</title>
|
||||
<style>
|
||||
body {
|
||||
padding: 20px;
|
||||
font-family: Arial;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 8px 16px;
|
||||
margin: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#log {
|
||||
margin-top: 20px;
|
||||
padding: 10px;
|
||||
border: 1px solid #ccc;
|
||||
height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h2>Python ↔ JS 双向通信</h2>
|
||||
|
||||
<!-- JS 调用 Python 函数(同步) -->
|
||||
<div>
|
||||
<input type="text" id="nameInput" placeholder="输入姓名" />
|
||||
<button onclick="callPythonSync()">调用 Python 同步函数</button>
|
||||
</div>
|
||||
|
||||
<!-- JS 调用 Python 异步函数 -->
|
||||
<div>
|
||||
<input
|
||||
type="number"
|
||||
id="durationInput"
|
||||
placeholder="异步任务耗时(秒)"
|
||||
value="2"
|
||||
/>
|
||||
<button onclick="callPythonAsync()">调用 Python 异步函数</button>
|
||||
</div>
|
||||
|
||||
<!-- 关闭窗口 -->
|
||||
<button onclick="callPythonCloseWindow()">关闭窗口</button>
|
||||
|
||||
<!-- 日志显示区域 -->
|
||||
<div id="log"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// ---------------------- 1. JS 调用 Python 函数 ----------------------
|
||||
// 同步调用
|
||||
async function callPythonSync() {
|
||||
const name = document.getElementById("nameInput").value || "匿名用户";
|
||||
try {
|
||||
// 核心:通过 window.pywebview.api 调用 Python 函数
|
||||
const result = await window.pywebview.api.python_hello(name);
|
||||
addLog(`[JS] 调用 Python 同步函数成功:${result}`);
|
||||
} catch (e) {
|
||||
addLog(`[JS] 调用 Python 同步函数失败:${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 异步调用(Python 执行完后主动回调 JS)
|
||||
async function callPythonAsync() {
|
||||
const duration = document.getElementById("durationInput").value;
|
||||
try {
|
||||
const result = await window.pywebview.api.python_async_task(duration);
|
||||
addLog(`[JS] 调用 Python 异步函数成功:${result}`);
|
||||
} catch (e) {
|
||||
addLog(`[JS] 调用 Python 异步函数失败:${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 调用 Python 关闭窗口
|
||||
async function callPythonCloseWindow() {
|
||||
await window.pywebview.api.python_close_window();
|
||||
}
|
||||
|
||||
// ---------------------- 2. 供 Python 调用的 JS 函数 ----------------------
|
||||
function js_receive_python_msg(msg) {
|
||||
addLog(`[JS] 收到 Python 消息:${msg}`);
|
||||
}
|
||||
|
||||
// ---------------------- 辅助函数:添加日志 ----------------------
|
||||
function addLog(text) {
|
||||
const logDiv = document.getElementById("log");
|
||||
const time = new Date().toLocaleTimeString();
|
||||
logDiv.innerHTML += `[${time}] ${text}<br>`;
|
||||
// 自动滚动到底部
|
||||
logDiv.scrollTop = logDiv.scrollHeight;
|
||||
}
|
||||
|
||||
// 页面加载完成后提示
|
||||
window.onload = () => {
|
||||
addLog("页面加载完成,可开始双向通信测试");
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
76
templates/app_JsToPy.py
Normal file
76
templates/app_JsToPy.py
Normal file
@@ -0,0 +1,76 @@
|
||||
import webview
|
||||
import threading
|
||||
import time,os
|
||||
|
||||
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# ---------------------- 1. 定义供 JS 调用的 Python 函数 ----------------------
|
||||
class Api:
|
||||
"""暴露给 JS 的 Python 接口类(所有方法都会被 JS 访问)"""
|
||||
def __init__(self):
|
||||
self.window = None # 保存窗口实例,用于 Python 主动调用 JS
|
||||
|
||||
def set_window(self, window):
|
||||
"""初始化时绑定窗口实例"""
|
||||
self.window = window
|
||||
|
||||
def python_hello(self, name):
|
||||
"""JS 调用的同步函数:接收参数,返回结果"""
|
||||
print(f"[Python] 收到 JS 调用,参数:{name}")
|
||||
return f"Hello {name}! 这是 Python 返回的消息"
|
||||
|
||||
def python_async_task(self, duration):
|
||||
"""JS 调用的异步函数:模拟耗时任务(不阻塞前端)"""
|
||||
def async_task():
|
||||
print(f"[Python] 开始异步任务,耗时 {duration} 秒")
|
||||
time.sleep(int(duration))
|
||||
# 异步任务完成后,主动调用 JS 函数通知结果
|
||||
self.window.evaluate_js(f'js_receive_python_msg("异步任务完成!耗时 {duration} 秒")')
|
||||
print(f"[Python] 异步任务结束")
|
||||
|
||||
# 启动子线程执行异步任务,避免阻塞 UI
|
||||
threading.Thread(target=async_task, daemon=True).start()
|
||||
return "异步任务已启动,请等待结果通知"
|
||||
|
||||
def python_close_window(self):
|
||||
"""JS 调用关闭窗口"""
|
||||
print("[Python] 收到关闭窗口请求")
|
||||
self.window.destroy()
|
||||
|
||||
# ---------------------- 2. Python 主动调用 JS 函数 ----------------------
|
||||
def python_call_js_periodically(window):
|
||||
"""Python 定时调用 JS 函数(模拟主动推送数据)"""
|
||||
count = 0
|
||||
while window.is_alive():
|
||||
count += 1
|
||||
# 执行 JS 函数,传递参数
|
||||
window.evaluate_js(f'js_receive_python_msg("Python 主动推送:第 {count} 条消息")')
|
||||
time.sleep(3) # 每 3 秒推送一次
|
||||
if count >= 5:
|
||||
break
|
||||
|
||||
# ---------------------- 3. 启动窗口 ----------------------
|
||||
if __name__ == "__main__":
|
||||
# 创建 API 实例
|
||||
api = Api()
|
||||
|
||||
# 加载本地 HTML 文件(也可加载远程 URL:url="https://xxx.com")
|
||||
window = webview.create_window(
|
||||
title="PyWebView 双向通信示例",
|
||||
url=f"file:///{CURRENT_DIR}/templates/app_JsToPy.html",
|
||||
resizable=True,
|
||||
js_api=api # 关键:暴露 Python API 给 JS
|
||||
)
|
||||
|
||||
# 绑定窗口实例到 API(供异步任务调用 JS)
|
||||
api.set_window(window)
|
||||
|
||||
# 启动 Python 主动调用 JS 的线程(非阻塞)
|
||||
t = threading.Thread(target=python_call_js_periodically, args=(window,), daemon=True)
|
||||
t.start()
|
||||
|
||||
# 运行窗口(阻塞主线程)
|
||||
webview.start(
|
||||
debug=True, # 开发环境开启调试,生产环境关闭
|
||||
http_server=True # 启用内置 HTTP 服务器(加载本地 HTML 必需)
|
||||
)
|
||||
Reference in New Issue
Block a user