Python使用pywebview开发桌面应用

前言

之前用了Eel做的桌面应用觉得已经够屌了,不过由于Eel是调用Chrome,时常出现各种小问题,比如窗口大小设置后有时候不管用,鼠标右键菜单无法禁用(一眼就能看出来是个web).而且尝试了用pyinstaller打包后文件好大,昨天晚上闲逛又发现了个比Eel更好的解决方案pywebview,更轻量,可自定义的设置更多.
由于pywebview是直接调用系统自身的浏览器(Win10调用Edge,Win7调用IE),因此很适合打包发布.
官网:https://pywebview.flowrl.com/

最简单应用上手

先装上轮子

pip install pywebview

实现一个内嵌百度首页的winform程序,固定窗口大小,禁止选择文字

"""
main.py
"""
import webview

window = webview.create_window(
    title='百度一下,全是广告',
    url='http://www.baidu.com',
    width=850,
    height=600,
    resizable=False,    # 固定窗口大小
    text_select=False,   # 禁止选择文字内容
    confirm_close=True   # 关闭时提示
)
webview.start()

在这里插入图片描述
无论是启动速度,还是显示效果都要比Eel好很多.
退出提示的窗口默认显示的是英文,可以本地化一下,定义个字典传给webview.start()当启动参数就行了.

chinese = {
    'global.quitConfirmation': u'确定关闭?',
}
webview.start(localization=chinese)

在这里插入图片描述

高阶应用

在HTML前端界面中调用Python中的函数并返回结果

基本流程:

  1. 定义一个类,这里叫Api
  2. Api类中定义要被前端调用的各种函数
  3. 定义一个window对象的时候加入参数js_api=api,api是实例化的Api类对象,将上面定义的Api类传给window以供js调用
  4. 前端js调用的语法为pywebview.api.函数名(参数).then(回调js函数)
    直接上代码吧:

Python

Http是由Flask提供的,这里不介绍了

"""
main.py
"""
import webview

chinese = {
    'global.quitConfirmation': u'确定关闭?',
}

class Api:

    def func(self, txt):
        response = {
            'message': '从Python调用函数返回内容:' + txt
        }
        return response


if __name__ == '__main__':
    api = Api()
    window = webview.create_window(
        title='天涯海角',
        url='http://127.0.0.1:5000/demo',
        width=760,
        height=390,
        # resizable=False,  # 固定窗口大小
        text_select=False,  # 禁止选择文字内容
        # confirm_close=True,  # 关闭时提示
        js_api=api  # 将上面实例化后的Api对象传给前端js调用
    )
    webview.start(localization=chinese)


HTML

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title>Document</title>
	<link rel="stylesheet" type="text/css" href="https://www.layuicdn.com/layui/css/layui.css" />
	<style>
		.setting-label {
			width: 150px;
		}
	</style>
</head>

<body>
	<div class="layui-container">
		<div class="layui-form">
			<fieldset class="layui-elem-field layui-field-title" style="margin-top: 20px;">
				<legend>商品信息采集</legend>
			</fieldset>
			<div class="layui-form-item">
				<label class="layui-form-label">请粘贴网址</label>
				<div class="layui-input-block">
					<input type="text" id="url" lay-verify="title" autocomplete="off"
						placeholder="支持淘宝/速卖通搜索结果与单独详情页面地址" class="layui-input">
				</div>
			</div>
			<div class="layui-form-item">
				<div class="layui-input-block">
					<button type="submit" class="layui-btn" lay-submit="" lay-filter="demo1"
						onclick="startJob()">开始采集</button>
					<button type="reset" class="layui-btn layui-btn-primary">重置</button>
					<button type="button" class="layui-btn layui-btn-danger layui-btn-radius layui-layout-right"
						onclick="openSetting()" style="display:none"><i class="layui-icon layui-icon-set"></i></button>
				</div>
			</div>
			<fieldset class="layui-elem-field layui-field-title" style="margin-top: 20px;">
				<legend>任务控制台</legend>
			</fieldset>
			<div class="layui-form-item layui-form-text">
				<label class="layui-form-label">输出信息:</label>
				<div class="layui-input-block">
					<textarea id="console" placeholder="开始采集后会在这里显示任务详细状态信息" class="layui-textarea" rows="6"></textarea>
				</div>
			</div>
		</div>
	</div>

	<!-- 设置弹出层 -->
	<div id="setting" class="layui-fluid" style="display:none">

		<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
			<legend>批量抓取任务参数</legend>
		</fieldset>
		<div class="layui-form-item">
			<label class="layui-form-label setting-label">并发任务数量:</label>
			<div class="layui-input-inline">
				<input type="number" name="task_num" lay-verify="required" placeholder="请输入" autocomplete="off"
					class="layui-input">
			</div>
		</div>
		<div class="layui-form-item">
			<label class="layui-form-label setting-label">商品详情采集图片数量:</label>
			<div class="layui-input-inline">
				<input type="number" name="pic_num" lay-verify="required" placeholder="请输入" autocomplete="off"
					class="layui-input">
			</div>
		</div>
		<div class="layui-form-item">
			<div class="layui-input-block">
				<button type="submit" class="layui-btn" lay-submit="">保存</button>
				<button type="reset" class="layui-btn layui-btn-primary">取消</button>
			</div>
		</div>


	</div>
	<script src="https://cdn.bootcss.com/jquery/1.9.1/jquery.min.js"></script>
	<script src="https://www.layuicdn.com/layui/layui.all.js"></script>
	<script>
		var layer = layui.layer;
		var form = layui.form;
		
		function output(res) {
				$("#console").val(res.message)
			}

		function startJob() {
			var url = $("#url").val();
			pywebview.api.startJob(url).then(output);
		}

		function openSetting() {
			// 打开弹出遮罩层
			layer.open({
				type: 1,
				title: '参数设置',
				area: ['600px', '300px'],
				shadeClose: true,
				content: $('#setting')
			});
		}
	
	</script>
</body>

</html>

打包成单个EXE文件

打包需要将关键的三个DLL文件一并打进去,所以首先需要复制这几个文件到Python代码根目录下:

.\venv\Lib\site-packages\webview\lib\WebBrowserInterop.x64.dll
.\venv\Lib\site-packages\webview\lib\WebBrowserInterop.x86.dll
.\venv\Lib\site-packages\webview\lib\Microsoft.Toolkit.Forms.UI.Controls.WebView.dll

如果是跑了Flask应用提供HTTP服务,那么还需要额外将templatesstatic文件夹也打包进去,完整的命令如下:

pyinstaller -w -F --add-data "templates;templates" --add-data "static;static" --add-data "WebBrowserInterop.x86.dll;./" --add-data "WebBrowserInterop.x64.dll;./" --add-data
 "Microsoft.Toolkit.Forms.UI.Controls.WebView.dll;./" --onefile -y main.py

实现目标
在服务器端设计好界面,用webview封装成一个exe文件,运行后加载服务器端的html界面,点击界面上的按钮通过js和python函数进行互动.

发布了181 篇原创文章 · 获赞 82 · 访问量 41万+

猜你喜欢

转载自blog.csdn.net/lpwmm/article/details/102998126
今日推荐