当前位置: 首页 > news >正文

tkwebview-tkinter的web视图

tkwebview-tkinter的web视图

  • 引言
  • 添加尺寸填充方法
  • 封装
    • 核心类
    • TkWebview
  • 示例
  • 关于跨平台

引言

我又来倒腾tkinter的web视图了😭。

很久以前实现了tkwebview2,在Windows平台上使用WebView2,这需要pywebviewpythonnet,大动干戈,而且在python层面中还写了很多底层方法的调用,到头来也没弄清pywebviewjs_api怎么搞😭。

那干脆用c/c++封装完,在python里写统一的接口就得了。

感谢webview/webview和HIllya51/webviewpy,巨人的肩膀。

添加尺寸填充方法

在原版的webview中,set_size只对独立窗口模式有效,我们期望tkwebview基于Frame,显然是用不了这个函数的。虽然webviewpy给出了在tkinter中使用的示例,但是使用了user32.dll,为了给跨平台留出可能,并且得到一个简单易用的webview控件,有必要将尺寸填充写进webview中,而在python层面封装为一个控件即可。

我单独维护了一个基于webview的c++库Smart-Space/webview,并在里面添加我需要的函数。

其实这一步很简单,直接调用resize_widget,我就不说明了,详见源码。

接下来就是编译,由于条件限制,我只实现了Windows平台下的尺寸填充方法,并在tkwebview中提供了动态链接库(32位未测试,但理论上和64位一样的)。

封装

核心类

这部分来自webviewpy,我只额外添加了webview_resize方法,不过这个函数只在内部用到。

TkWebview

一个真正的tkinter控件。

class TkWebview(Frame):def __init__(self, master=None, **kwargs):Frame.__init__(self, master, bg='black', **kwargs)self.update()self.webview = Webview(debug=False, window=self.winfo_id())self.bind('<Configure>', self.on_configure)def on_configure(self, event):self.webview.resize()def resolve(self, id, status, result):return self.webview.resolve(id, status, result)def bindjs(self, name, fn, is_async_return=False):return self.webview.bind(name, fn, is_async_return)def dispatch(self, fn):return self.webview.dispatch(fn)def unbindjs(self, name):return self.webview.unbind(name)def eval(self, js):return self.webview.eval(js)def navigate(self, url):return self.webview.navigate(url)def init(self, js):return self.webview.init(js)def set_html(self, html):return self.webview.set_html(html)def version(self):return self.webview.version()

其含义见Smart-Space/tkwebview: tkinter webview control。

Win11前需要安装WebView2 Runtime,这个自行想办法判断吧😵。

示例

pip install tkwebview

tkwebview不是比tkwebview2低一等,而是TkWebView和Tk-WebView2,两个东西,虽然在Windows上用的WebView2。

以下为示例代码:

from tkinter import Tk, Entry
from tkwebview import TkWebview as Webview
import ctypes
from threading import Thread
from time import sleep
ScaleFactor = ctypes.windll.shcore.GetScaleFactorForDevice(0)/100
ctypes.windll.shcore.SetProcessDpiAwareness(1)def get_url(event):# 需要以协议(https, http, file等)开头url=e.get()web.navigate(url)def count(req):global count_numcount_num += reqreturn str(count_num)def compute(returner, num1, num2):def _(_1, _2):sleep(1)returner(_1 * _2)Thread(target=_,args=(num1, num2),).start()a=Tk()
a.tk.call('tk', 'scaling', ScaleFactor)
a.geometry('800x400')e=Entry(a,font='微软雅黑 18', relief='solid')
e.pack(fill='x', padx=10, pady=5)
e.bind('<Return>', get_url)html="""
<div><button id=\"increment\">+</button><button id=\"decrement\">−</button><span>Counter: <span id=\"counterResult\">0</span></span>
</div>
<hr />
<div><button id=\"compute\">Compute</button><span>Result: <span id=\"computeResult\">(not started)</span></span>
</div>
<script type=\"module\">const getElements = ids => Object.assign({}, ...ids.map(id => ({ [id]: document.getElementById(id) })));const ui = getElements([\"increment\", \"decrement\", \"counterResult\", \"compute\",\"computeResult\"]);ui.increment.addEventListener(\"click\", async () => {ui.counterResult.textContent = await window.count(1);});ui.decrement.addEventListener(\"click\", async () => {ui.counterResult.textContent = await window.count(-1);});ui.compute.addEventListener(\"click\", async () => {ui.compute.disabled = true;ui.computeResult.textContent = \"(pending)\";ui.computeResult.textContent = await window.compute(6, 7);ui.compute.disabled = false;});
</script>"""count_num = 0web=Webview(a)
web.pack(fill='both', expand=True)
# web.navigate('https://www.baidu.com/')
web.set_html(html)
web.bindjs('count', count)
web.bindjs('compute', compute, is_async_return=True)a.bind_all("<Button-1>", lambda e: e.widget.focus_force())
# 如果某个控件同样需要<Button-1>,可自行改写或者使用add参数添加a.mainloop()

关于焦点问题,这里的注释和项目简介里都有说明。

效果(这次支持从JS中调用python代码了😋):

在这里插入图片描述

关于跨平台

首先,webview是跨平台的,webviewpy也支持跨平台判断,理论上tkwebview是可以做到跨平台的,唯一的难点就是实现跨平台的webview_resize,这个也很简单,因为webview本身提供了实现这个功能的方法。但是,条件限制,我无法编译和测试其他平台下的tkwebview。

以上代码库均为MIT协议开源,完全可以放到本地自行编写合适的webview方法,包括现在还不支持的事件回调(因为我不确定其它webkit支持情况如何)。

Linux下好像不需要实现webview_resize,GTK自己会处理,如果tkinter是用GTK实现的话,但好像不是,是X11,那就不好搞了,不过反正我不需要😵😭🤣。
在本文初次发布之后的一个小时里,我又看了Mac上的源码,如果基于Cocoa的tkinter,也不用单独实现webview_resize,因为使用了NSViewWidthSizable | NSViewHeightSizable,基于X11也难办🤣😭😵。
那我之后就看看Windows下有什么好玩的吧。

http://www.dtcms.com/a/317716.html

相关文章:

  • 解决云服务器端口无法访问的方法
  • java学习 leetcode24交换链表节点 200岛屿数量 +一些开发任务
  • Redis(七):Redis高并发高可用(主从复制)
  • JP3-4-MyClub后台前端(二)
  • C++、STL面试题总结(三)
  • 考研408_数据结构笔记(第四章 串)
  • 第五十一章:AI模型服务的“百变面孔”:WebUI/CLI/脚本部署全解析
  • 功能安全和网络安全的综合保障流程
  • Transformers简单介绍 - 来源于huggingface
  • 虚幻GAS底层原理解剖五 (AS)
  • 从案例学习cuda编程——线程模型和显存模型
  • git 清理submodule
  • PowerShell部署Windows爬虫自动化方案
  • 【ArcGIS】分区统计中出现Null值且Nodata无法忽略的问题以及shp擦除(erase)的使用——以NDVI去水体为例
  • DevOps时代的知识基座革命:Gitee Wiki如何重构研发协作范式
  • Unity轻量观察相机
  • 利用DeepSeek编写go语言按行排序程序
  • centos配置java环境变量
  • Go语言 单元测试
  • 后端服务oom
  • 商品详情数据的秒级更新如何运用京东 API 实现?
  • Debian系统更新实现
  • Docker国内可用镜像(2025.08.06测试)
  • 【QT】-windous 应用程序开机自启
  • 组合期权:跨式策略
  • 【数字图像处理系列笔记】Ch03:图像的变换
  • Node.js- express的基本使用
  • MyBatis增删改、RESTful API 风格、SpringAOP
  • 启动模块服务时报错:docker: Error response from daemon: Conflict.
  • 状态模式及优化