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也可以。


文件结构

python tk 文件浏览器 tkinter内置浏览器_xml

  • 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()

最终效果

python tk 文件浏览器 tkinter内置浏览器_python_02

现在的问题

现在的问题主要有以下几个方面:

  1. 输入框在webview2获得焦点后就失效了,需要本窗口失去焦点,再次点击输入框才行
  2. 目前还没有想到直接打开新窗口的好方法,只能在本窗口打开
  3. 将新窗口的内容在本页面打开后,历史记录清零
  4. 菜单调不出来

结语

虽然真的是有点漏洞百出,但是至少是可以正常使用的。网址输入可以直接使用搜索界面,浏览器历史的话,应该不是很重要。。。总之,凑合着用用,当个示例还是够的。

虽然tkwebview2说是维护中,但是我几乎没怎么碰tkwebview2,也是希望需要的人对其完善。

🔆tkinter创新🔆