• 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

    
    <tinui>
        <line x='5'>
            <notebook width='1270' height='710'>ntbnotebook>
        line>
    tinui>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    其实很简单,就一个标签栏视图,也叫做选项卡(notebook)。

    页面

    page.xml

    <tinui>
        <line>
            <button text='<'>backbuttonbutton>
            <button text='>'>forebuttonbutton>
            <button text=''>refbuttonbutton>
            <entry width='1000'>urlenterentry>
            <button text='🏠'>homebuttonbutton>
            <button text=''>colbuttonbutton>
        line>
        <line>
        line>
    tinui>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这个界面也甚为简单,到后面发现其实输入框很废。

    程序启动

    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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    页面加载

    这个函数为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('',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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    其它代码就很简单了。

    源文件代码

    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('https://blog.csdn.net/tinga_kilin')
    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('',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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119

    最终效果

    在这里插入图片描述

    现在的问题

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

    1. 输入框在webview2获得焦点后就失效了,需要本窗口失去焦点,再次点击输入框才行

    2. 目前还没有想到直接打开新窗口的好方法,只能在本窗口打开

    3. 将新窗口的内容在本页面打开后,历史记录清零

    4. 菜单调不出来


    结语

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

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

    🔆tkinter创新🔆

  • 相关阅读:
    软考高级系统架构设计师系列之:系统开发基础知识
    三、Eclipse 修改字符集
    Leo赠书活动-07期 【嵌入式虚拟化技术与应用】文末送书
    SQL介绍
    AI智能网关在工业物联网领域有哪些应用优势
    flume使用实例
    聚苯乙烯/聚4-乙烯基吡啶功能微球/CF3-PPFPA-PS聚苯胺/聚苯乙烯微球的制备
    Sublime合并生成,同时编辑三页代码和文本框
    Spring
    HTTPS对HTTP的加密过程
  • 原文地址:https://blog.csdn.net/tinga_kilin/article/details/126069204