tkinter-TinUI-xml实战(8)轻型浏览器
- 引言
- 声明
- 文件结构
- 核心代码
- 窗口布局
- 页面
- 程序启动
- 页面加载
- 源文件代码
- 最终效果
- 现在的问题
- 结语
引言
在此之前,我将pywebview中的WebView2(ChromeEdge)分离出来,用来给tkinter做网页控件,诞生了tkwebview2。此外,TinUI也拥有了标签栏视图(选项卡)notebook元素控件。所以突发奇想,用TinUI给tkwebview2写一个小小的、十分简易、又漏洞百出的轻型浏览器。
有人问我tkwebview2是不是只能在win使用。其实是但又不是,只要在其它系统能够运行类似 .Net 的环境,并且能够运行pywebview的chormeedge模式,再加上webview2 runtime,然后该系统能够允许窗口嵌套(不能用user32,需要自己找找有什么办法,然后在源码更改),就可以使用tkwebview2了。
途中遇到一些莫名其妙的问题,我还没办法解决,不过可以凑合着用了。
声明
本项目属于作者原创。借鉴了GitHub/TinUI上的tuxml.py
,翻版必究,但可以自行添加功能代码。
本项目使用的TinUI为我开源并维护在GitHub上的主文件——TinUI.py。当然,使用PYPI中下载安装的tinui也可以。
文件结构
- main.xml - 整体窗口布局
- page.xml - 每个页面的布局
- tinui.py - TinUI核心支持
- tinuiweb.py - 逻辑代码
核心代码
窗口布局
main.xml
<!--TinUIXml编辑器-->
<tinui>
<line x='5'>
<notebook width='1270' height='710'>ntb</notebook>
</line>
</tinui>
其实很简单,就一个标签栏视图,也叫做选项卡(notebook)。
页面
page.xml
<tinui>
<line>
<button text='<'>backbutton</button>
<button text='>'>forebutton</button>
<button text='↺'>refbutton</button>
<entry width='1000'>urlenter</entry>
<button text='🏠'>homebutton</button>
<button text='?'>colbutton</button>
</line>
<line>
</line>
</tinui>
这个界面也甚为简单,到后面发现其实输入框很废。
程序启动
def main():
global root,u,ntb,xml,pagexml
root=Tk()
root.geometry('1280x720+5+5')
root.title('TinUI 轻型浏览器')
root.resizable(0,0)
u=BasicTinUI(root)
u.pack(fill='both',expand=True)
x=TinUIXml(u)
#in
#during
with open('main.xml',mode='r',encoding='utf-8') as f:
xml=f.read()
x.loadxml(xml)
with open('page.xml',mode='r',encoding='utf-8') as f:
pagexml=f.read()
#out
ntb = x.tags["ntb"][-2]
newpage(url='https://www.baidu.com/')
ntb.cannew(True,newpage)
root.mainloop()
def go():
try:
main()
except Exception as err:
print(err)
t = Thread(ThreadStart(go))
t.ApartmentState = ApartmentState.STA
t.Start()
t.Join()
页面加载
这个函数为newpage
,但是考虑到点击新增标签页的功能,就把这个函数写的通用一点。
def newpage(title='新标签页',url='https://bing.com/'):
npage=ntb.addpage('新标签页')
ntb.showpage(npage)
nu,nx,_=ntb.getuis(npage)
nx.loadxml(pagexml)
#---
webview=WebView2(nu,width=1260,height=620)
nu.create_window((5,40),window=webview,anchor='nw')
#---
backbutton = nx.tags["backbutton"][-2]
backbutton[0](lambda event:backone(webview))
forebutton = nx.tags["forebutton"][-2]
forebutton[0](lambda event:foreone(webview))
refbutton = nx.tags["refbutton"][-2]
refbutton[0](lambda event:refreshone(webview))
urlenter,uid = nx.tags["urlenter"]
urlenter.bind('<Return>',lambda event:newurl(webview,urlenter))
homebutton = nx.tags["homebutton"][-2]
homebutton[0](lambda event:homeone(webview))
colbutton = nx.tags["colbutton"][-2]
colbutton[0](lambda event:collect_it(webview))
#---
def loadit(sender,arg):
core=sender.CoreWebView2
core.NewWindowRequested+=newwindow
core.DocumentTitleChanged+=lambda s,a:titlechanged(s,a,urlenter,npage)
core.AreDevToolsEnabled=True
webview.web.CoreWebView2InitializationCompleted+=loadit
webview.web.ContentLoading+=lambda sender,args:newtitle(sender,args,urlenter,npage)
if url!='':
webview.load_url(url)
urlenter.insert(0,url)
nu.focus(uid)
return webview
其它代码就很简单了。
源文件代码
from tinui import *
from tkinter import Tk
from time import sleep
import threading
import clr
clr.AddReference('System.Threading')
from System.Threading import Thread,ApartmentState,ThreadStart,ParameterizedThreadStart
from tkwebview2.tkwebview2 import WebView2
def backone(wb):
wb.web.GoBack()
def foreone(wb):
wb.web.GoForward()
def refreshone(wb):
wb.web.Reload()
def newurl(wb,entry):
url=entry.get()
if url!='':
wb.load_url(url)
wb.web.Enabled=True
def newtitle(wb,args,entry,flag):#更新标题
try:
url=wb.Source.ToString()
entry.delete(0,'end')
entry.insert(0,url)
except Exception as err:
print(err)
def newwindow(sender,args):
try:
args.Handle=True
args.NewWindow=sender
except Exception as err:
print(err)
def titlechanged(sender,args,entry,flag):
title=sender.DocumentTitle
threading.Thread(target=ntb.newtitle,args=(flag,title)).start()
def homeone(wb):
wb.load_url('')
def collect_it(wb):#收藏,暂不用
...
def newpage(title='新标签页',url='https://bing.com/'):
npage=ntb.addpage('新标签页')
ntb.showpage(npage)
nu,nx,_=ntb.getuis(npage)
nx.loadxml(pagexml)
#---
webview=WebView2(nu,width=1260,height=620)
nu.create_window((5,40),window=webview,anchor='nw')
#---
backbutton = nx.tags["backbutton"][-2]
backbutton[0](lambda event:backone(webview))
forebutton = nx.tags["forebutton"][-2]
forebutton[0](lambda event:foreone(webview))
refbutton = nx.tags["refbutton"][-2]
refbutton[0](lambda event:refreshone(webview))
urlenter,uid = nx.tags["urlenter"]
urlenter.bind('<Return>',lambda event:newurl(webview,urlenter))
homebutton = nx.tags["homebutton"][-2]
homebutton[0](lambda event:homeone(webview))
colbutton = nx.tags["colbutton"][-2]
colbutton[0](lambda event:collect_it(webview))
#---
def loadit(sender,arg):
core=sender.CoreWebView2
core.NewWindowRequested+=newwindow
core.DocumentTitleChanged+=lambda s,a:titlechanged(s,a,urlenter,npage)
core.AreDevToolsEnabled=True
webview.web.CoreWebView2InitializationCompleted+=loadit
webview.web.ContentLoading+=lambda sender,args:newtitle(sender,args,urlenter,npage)
if url!='':
webview.load_url(url)
urlenter.insert(0,url)
nu.focus(uid)
return webview
def main():
global root,u,ntb,xml,pagexml
root=Tk()
root.geometry('1280x720+5+5')
root.title('TinUI 轻型浏览器')
root.resizable(0,0)
u=BasicTinUI(root)
u.pack(fill='both',expand=True)
x=TinUIXml(u)
#in
#during
with open('main.xml',mode='r',encoding='utf-8') as f:
xml=f.read()
x.loadxml(xml)
with open('page.xml',mode='r',encoding='utf-8') as f:
pagexml=f.read()
#out
ntb = x.tags["ntb"][-2]
newpage(url='https://www.baidu.com/')
ntb.cannew(True,newpage)
root.mainloop()
def go():
try:
main()
except Exception as err:
print(err)
t = Thread(ThreadStart(go))
t.ApartmentState = ApartmentState.STA
t.Start()
t.Join()
最终效果
现在的问题
现在的问题主要有以下几个方面:
- 输入框在webview2获得焦点后就失效了,需要本窗口失去焦点,再次点击输入框才行
- 目前还没有想到直接打开新窗口的好方法,只能在本窗口打开
- 将新窗口的内容在本页面打开后,历史记录清零
- 菜单调不出来
结语
虽然真的是有点漏洞百出,但是至少是可以正常使用的。网址输入可以直接使用搜索界面,浏览器历史的话,应该不是很重要。。。总之,凑合着用用,当个示例还是够的。
虽然tkwebview2说是维护中,但是我几乎没怎么碰tkwebview2,也是希望需要的人对其完善。
🔆tkinter创新🔆