pywebview桌面程序开发(技术路线:前端+Python,全网独一份!!!!!!)
空指针异常Null_Point_Ex 2024-06-27 09:03:03 阅读 68
一、pywebview
官网:https://pywebview.flowrl.com/
1、简介
pywebview声称Build GUI for your Python program with JavaScript, HTML, and CSS。就是可以使用web技术来实现桌面应用程序开发。其内核我理解仍然是浏览器,只不过将浏览器封装成系统窗口,这样就可以将web无缝切换到桌面应用,相比pyQt等重武器还是比较方便的。
对于目前比较火的electron,Python的加入给应用程序提供了上限,据说打包的大小也比electron小。
2、安装
pip install pywebview
Hello world 的demo:
import webview
webview.create_window('Hello world', 'https://pywebview.flowrl.com/')
webview.start()
3、依赖
windows程序依赖pythonnet(要求 > .NET 4.0),pythonnet可以让python调用.NET代码。
为了使用最新版本的 Chromium(Chromium是谷歌的开源项目,国产的所有 “双核浏览器”,都是基于 Chromium 开发的,甚至 Chrome 也是基于它。),需要安装WebView2。
选择Web应用还是原生应用来开发是一种在通用性和本地权限之前的权衡。WebApp兼容的范围很广,而且Web前端代码基于浏览器天生跨平台,而且前端框架多好开发。而原生应用有很大本地权限,可以进行各种文件和操作系统接口的调用。WebView可以结合这两者的优点进行开发。WebView2允许你在本地App里面嵌入web相关的技术(例如HTML,CSS和JavaScript)。WebView2控件使用微软的Edge作为渲染引擎,你可以嵌入一部分或者整个App都用WebView来做。
WebView2下载地址:https://developer.microsoft.com/en-us/microsoft-edge/webview2/?form=MA13LH
4、使用
4.1、最简单示例
import webview
window = webview.create_window('Woah dude!', 'https://pywebview.flowrl.com')
webview.start()
create_window:
返回窗口实例,该实例可以使用许多窗口操作和DOM函数,可创建任意数量窗口,在GUI循环启动后创建的窗口会立即显示。所有打开的窗口都以列表形式存储在webview.windows中。create_window第二个参数可以是url(远程url或本地url),也可设置html来加载html。html与url同时存在,html优先级高。
4.2、http server示例
pywebview提供一个与WSGI兼容的http服务器。
import webview
webview.create_window('Woah dude!', 'index.html')
webview.start(http_server=True)
将http_server设为true
一般使用外部WSGI兼容的http服务器,将服务器对象作为url传递
from flask import Flask
import webview
server = Flask(__name__, static_folder='./assets', template_folder='./templates')
webview.create_window('Flask example', server)
webview.start()
4.3、线程模型
webview.start会开启一个GUI循环,并且它是一个阻塞函数。当GUI循环被阻塞时,必须在一个单独的线程和进程中执行后端逻辑
。可以通过手动开启线程/进程,或者将函数作为要启动的第一个参数来启动。第二个参数设置函数的参数。这种方法会在后台启动一个线程,与手动起一个线程相同。
import webview
def custom_logic(window):
window.evaluate_js('alert("welcome")')
window = webview.create_window('Woah dude!', html='<h1>Woah dude!<h1>')
webview.start(custom_logic, window)
# anything below this line will be executed after program is finished executing
print(2)#只有窗口关闭了才能打印
4.4、Python与evaluate_js通信
在Python调用Javascript
使用evaluate_js可以在Python中调用Javascript 函数,如:window.evaluate_js(‘alert(“welcome”)’)
在Javascript 中调用Python
方法1(十分反人类):在一个Python类中先写一个html网页,在其中的Javascript 使用pywebview.api.方法名来调用Python函数,方法名不能以下划线开头。示例如下:
import random
import sys
import threading
import time
import webview
html = """
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<style>
#response-container {
display: none;
padding: 3rem;
margin: 3rem 5rem;
font-size: 120%;
border: 5px dashed #ccc;
}
label {
margin-left: 0.3rem;
margin-right: 0.3rem;
}
button {
font-size: 100%;
padding: 0.5rem;
margin: 0.3rem;
text-transform: uppercase;
}
</style>
</head>
<body>
<h1>JS API Example</h1>
<p id='pywebview-status'><i>pywebview</i> is not ready</p>
<button onClick="initialize()">Hello Python</button><br/>
<button id="heavy-stuff-btn" onClick="doHeavyStuff()">Perform a heavy operation</button><br/>
<button onClick="getRandomNumber()">Get a random number</button><br/>
<label for="name_input">Say hello to:</label><input id="name_input" placeholder="put a name here">
<button onClick="greet()">Greet</button><br/>
<button onClick="catchException()">Catch Exception</button><br/>
<div id="response-container"></div>
<script>
window.addEventListener('pywebviewready', function() {
var container = document.getElementById('pywebview-status')
container.innerHTML = '<i>pywebview</i> is ready'
})
function showResponse(response) {
var container = document.getElementById('response-container')
container.innerText = response.message
container.style.display = 'block'
}
function initialize() {
pywebview.api.init().then(showResponse)
}
function doHeavyStuff() {
var btn = document.getElementById('heavy-stuff-btn')
pywebview.api.doHeavyStuff().then(function(response) {
showResponse(response)
btn.onclick = doHeavyStuff
btn.innerText = 'Perform a heavy operation'
})
showResponse({message: 'Working...'})
btn.innerText = 'Cancel the heavy operation'
btn.onclick = cancelHeavyStuff
}
function cancelHeavyStuff() {
pywebview.api.cancelHeavyStuff()
}
function getRandomNumber() {
pywebview.api.getRandomNumber().then(showResponse)
}
function greet() {
var name_input = document.getElementById('name_input').value;
pywebview.api.sayHelloTo(name_input).then(showResponse)
}
function catchException() {
pywebview.api.error().catch(showResponse)
}
</script>
</body>
</html>
"""
class Api:
def __init__(self):
self.cancel_heavy_stuff_flag = False
def init(self):
response = { 'message': 'Hello from Python {0}'.format(sys.version)}
return response
def getRandomNumber(self):
response = {
'message': 'Here is a random number courtesy of randint: {0}'.format(
random.randint(0, 100000000)
)
}
return response
def doHeavyStuff(self):
time.sleep(0.1) # sleep to prevent from the ui thread from freezing for a moment
now = time.time()
self.cancel_heavy_stuff_flag = False
for i in range(0, 1000000):
_ = i * random.randint(0, 1000)
if self.cancel_heavy_stuff_flag:
response = { 'message': 'Operation cancelled'}
break
else:
then = time.time()
response = {
'message': 'Operation took {0:.1f} seconds on the thread {1}'.format(
(then - now), threading.current_thread()
)
}
return response
def cancelHeavyStuff(self):
time.sleep(0.1)
self.cancel_heavy_stuff_flag = True
def sayHelloTo(self, name):
response = { 'message': 'Hello {0}!'.format(name)}
return response
def error(self):
raise Exception('This is a Python exception')
if __name__ == '__main__':
api = Api()
window = webview.create_window('JS API example', html=html, js_api=api)
webview.start()
方法二:将Python函数公开到Javascript域,示例如下:
import webview
def lol():
print('LOL')
def wtf():
print('WTF')
def echo(arg1, arg2, arg3):
print(arg1)
print(arg2)
print(arg3)
def expose(window):
window.expose(echo) # expose a function during the runtime
window.evaluate_js('pywebview.api.lol()')
window.evaluate_js('pywebview.api.wtf()')
window.evaluate_js('pywebview.api.echo(1, 2, 3)')
if __name__ == '__main__':
window = webview.create_window(
'JS Expose Example', html='<html><head></head><body><h1>JS Expost</body></html>'
)
window.expose(lol, wtf) # expose functions beforehand
webview.start(expose, window, debug=True)
方法三(最实用):
运行一个PythonWeb服务,让前端代码对其API进行调用。对于将Web一直到应用程序非常便捷。
4.5、事件
Windows对象有许多声明周期事件,订阅事件使用+=语法,即windows.events.loaded+=函数名,事件触发时会调用该函数,不能重复订阅,多次订阅也只调用一次。取消订阅使用windows.events.loaded-=函数名。
events.closed:窗口关闭后触发的事件events.closing:窗口正在关闭,在确认时候触发的事件events.loaded:DOM准备就绪时触发的事件events.minimized:窗口最小化触发的事件events.restore:窗口恢复时触发的事件events.maximized:窗口最大化触发的事件events.resized:窗口大小变化时触发的事件events.shown:窗口显示时触发的事件
5、常用示例
5.1、10秒后改变加载的url
import time
import webview
def change_url(window):
# wait a few seconds before changing url:
time.sleep(10)
# change url:
window.load_url('https://pywebview.flowrl.com/hello')
if __name__ == '__main__':
window = webview.create_window('URL Change Example', 'http://www.google.com')
webview.start(change_url, window)
5.2、带有确认对话框的窗口
import webview
def open_confirmation_dialog(window):
result = window.create_confirmation_dialog('Question', 'Are you ok with this?')
if result:
print('User clicked OK')
else:
print('User clicked Cancel')
if __name__ == '__main__':
window = webview.create_window(
'Confirmation dialog example', 'https://pywebview.flowrl.com/hello'
)
webview.start(open_confirmation_dialog, window)
5.3、常用事件
import webview
def on_closed():
print('pywebview window is closed')
def on_closing():
print('pywebview window is closing')
def on_shown():
print('pywebview window shown')
def on_minimized():
print('pywebview window minimized')
def on_restored():
print('pywebview window restored')
def on_maximized():
print('pywebview window maximized')
def on_resized(width, height):
print(
'pywebview window is resized. new dimensions are {width} x {height}'.format(
width=width, height=height
)
)
def on_loaded():
print('DOM is ready')
# unsubscribe event listener
webview.windows[0].events.loaded -= on_loaded
webview.windows[0].load_url('https://pywebview.flowrl.com/hello')
def on_moved(x, y):
print('pywebview window is moved. new coordinates are x: {x}, y: {y}'.format(x=x, y=y))
if __name__ == '__main__':
window = webview.create_window(
'Simple browser', 'https://pywebview.flowrl.com/', confirm_close=True
)
window.events.closed += on_closed
window.events.closing += on_closing
window.events.shown += on_shown
window.events.loaded += on_loaded
window.events.minimized += on_minimized
window.events.maximized += on_maximized
window.events.restored += on_restored
window.events.resized += on_resized
window.events.moved += on_moved
webview.start(debug=True)
5.4、文件打开
import webview
def open_file_dialog(window):
file_types = ('Image Files (*.bmp;*.jpg;*.gif)', 'All files (*.*)')
result = window.create_file_dialog(
webview.OPEN_DIALOG, allow_multiple=True, file_types=file_types
)
print(result)#result为文件的绝对路径
if __name__ == '__main__':
window = webview.create_window('Open file dialog example', 'https://pywebview.flowrl.com/hello')
webview.start(open_file_dialog, window)
5.5、文件保存
import webview
def save_file_dialog(window):
import time
time.sleep(5)
result = window.create_file_dialog(
webview.SAVE_DIALOG, directory='/', save_filename='test.file'
)
print(result)
if __name__ == '__main__':
window = webview.create_window('Save file dialog', 'https://pywebview.flowrl.com/hello')
webview.start(save_file_dialog, window)
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。