|
一、pywebview官网:https://pywebview.flowrl.com/1、简介pywebview声称BuildGUIforyourPythonprogramwithJavaScript,HTML,andCSS。就是可以使用web技术来实现桌面应用程序开发。其内核我理解仍然是浏览器,只不过将浏览器封装成系统窗口,这样就可以将web无缝切换到桌面应用,相比pyQt等重武器还是比较方便的。对于目前比较火的electron,Python的加入给应用程序提供了上限,据说打包的大小也比electron小。2、安装pipinstallpywebview1Helloworld的demo:importwebviewwebview.create_window('Helloworld','https://pywebview.flowrl.com/')webview.start()1233、依赖windows程序依赖pythonnet(要求>.NET4.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=MA13LH4、使用4.1、最简单示例importwebviewwindow=webview.create_window('Woahdude!','https://pywebview.flowrl.com')webview.start()1234create_window:返回窗口实例,该实例可以使用许多窗口操作和DOM函数,可创建任意数量窗口,在GUI循环启动后创建的窗口会立即显示。所有打开的窗口都以列表形式存储在webview.windows中。create_window第二个参数可以是url(远程url或本地url),也可设置html来加载html。html与url同时存在,html优先级高。4.2、httpserver示例pywebview提供一个与WSGI兼容的http服务器。importwebviewwebview.create_window('Woahdude!','index.html')webview.start(http_server=True)1234将http_server设为true一般使用外部WSGI兼容的http服务器,将服务器对象作为url传递fromflaskimportFlaskimportwebviewserver=Flask(__name__,static_folder='./assets',template_folder='./templates')webview.create_window('Flaskexample',server)webview.start()1234564.3、线程模型webview.start会开启一个GUI循环,并且它是一个阻塞函数。当GUI循环被阻塞时,必须在一个单独的线程和进程中执行后端逻辑。可以通过手动开启线程/进程,或者将函数作为要启动的第一个参数来启动。第二个参数设置函数的参数。这种方法会在后台启动一个线程,与手动起一个线程相同。importwebviewdefcustom_logic(window):window.evaluate_js('alert("welcome")')window=webview.create_window('Woahdude!',html='
Woahdude!
')webview.start(custom_logic,window)#anythingbelowthislinewillbeexecutedafterprogramisfinishedexecutingprint(2)#只有窗口关闭了才能打印1234567894.4、Python与evaluate_js通信在Python调用Javascript使用evaluate_js可以在Python中调用Javascript函数,如:window.evaluate_js(‘alert(“welcome”)’)在Javascript中调用Python方法1(十分反人类):在一个Python类中先写一个html网页,在其中的Javascript使用pywebview.api.方法名来调用Python函数,方法名不能以下划线开头。示例如下:importrandomimportsysimportthreadingimporttimeimportwebviewhtml="""
JSAPIExample
pywebviewisnotreadyHelloPython
Performaheavyoperation
Getarandomnumber
Sayhelloto:Greet
CatchException
"""classApi:def__init__(self):self.cancel_heavy_stuff_flag=Falsedefinit(self):response={'message':'HellofromPython{0}'.format(sys.version)}returnresponsedefgetRandomNumber(self):response={'message':'Hereisarandomnumbercourtesyofrandint:{0}'.format(random.randint(0,100000000))}returnresponsedefdoHeavyStuff(self):time.sleep(0.1)#sleeptopreventfromtheuithreadfromfreezingforamomentnow=time.time()self.cancel_heavy_stuff_flag=Falseforiinrange(0,1000000):_=i*random.randint(0,1000)ifself.cancel_heavy_stuff_flag:response={'message':'Operationcancelled'}breakelse:then=time.time()response={'message':'Operationtook{0:.1f}secondsonthethread{1}'.format((then-now),threading.current_thread())}returnresponsedefcancelHeavyStuff(self):time.sleep(0.1)self.cancel_heavy_stuff_flag=TruedefsayHelloTo(self,name):response={'message':'Hello{0}!'.format(name)}returnresponsedeferror(self):raiseException('ThisisaPythonexception')if__name__=='__main__':api=Api()window=webview.create_window('JSAPIexample',html=html,js_api=api)webview.start()123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151方法二:将Python函数公开到Javascript域,示例如下:importwebviewdeflol():print('LOL')defwtf():print('WTF')defecho(arg1,arg2,arg3):print(arg1)print(arg2)print(arg3)defexpose(window):window.expose(echo)#exposeafunctionduringtheruntimewindow.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('JSExposeExample',html='
JSExpost')window.expose(lol,wtf)#exposefunctionsbeforehandwebview.start(expose,window,debug=True)123456789101112131415161718192021222324252627方法三(最实用):运行一个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秒后改变加载的urlimporttimeimportwebviewdefchange_url(window):#waitafewsecondsbeforechangingurl:time.sleep(10)#changeurl:window.load_url('https://pywebview.flowrl.com/hello')if__name__=='__main__':window=webview.create_window('URLChangeExample','http://www.google.com')webview.start(change_url,window)12345678910111213145.2、带有确认对话框的窗口importwebviewdefopen_confirmation_dialog(window):result=window.create_confirmation_dialog('Question','Areyouokwiththis?')ifresult:print('UserclickedOK')else:print('UserclickedCancel')if__name__=='__main__':window=webview.create_window('Confirmationdialogexample','https://pywebview.flowrl.com/hello')webview.start(open_confirmation_dialog,window)12345678910111213145.3、常用事件importwebviewdefon_closed():print('pywebviewwindowisclosed')defon_closing():print('pywebviewwindowisclosing')defon_shown():print('pywebviewwindowshown')defon_minimized():print('pywebviewwindowminimized')defon_restored():print('pywebviewwindowrestored')defon_maximized():print('pywebviewwindowmaximized')defon_resized(width,height):print('pywebviewwindowisresized.newdimensionsare{width}x{height}'.format(width=width,height=height))defon_loaded():print('DOMisready')#unsubscribeeventlistenerwebview.windows[0].events.loaded-=on_loadedwebview.windows[0].load_url('https://pywebview.flowrl.com/hello')defon_moved(x,y):print('pywebviewwindowismoved.newcoordinatesarex:{x},y:{y}'.format(x=x,y=y))if__name__=='__main__':window=webview.create_window('Simplebrowser','https://pywebview.flowrl.com/',confirm_close=True)window.events.closed+=on_closedwindow.events.closing+=on_closingwindow.events.shown+=on_shownwindow.events.loaded+=on_loadedwindow.events.minimized+=on_minimizedwindow.events.maximized+=on_maximizedwindow.events.restored+=on_restoredwindow.events.resized+=on_resizedwindow.events.moved+=on_movedwebview.start(debug=True)12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535.4、文件打开importwebviewdefopen_file_dialog(window):file_types=('ImageFiles(*.bmp;*.jpg;*.gif)','Allfiles(*.*)')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('Openfiledialogexample','https://pywebview.flowrl.com/hello')webview.start(open_file_dialog,window)123456789101112135.5、文件保存importwebviewdefsave_file_dialog(window):importtimetime.sleep(5)result=window.create_file_dialog(webview.SAVE_DIALOG,directory='/',save_filename='test.file')print(result)if__name__=='__main__':window=webview.create_window('Savefiledialog','https://pywebview.flowrl.com/hello')webview.start(save_file_dialog,window)1234567891011121314
|
|