python:tkinter + cef 模仿 mdict 界面

cefpython3 其上游是C++开发的CEF(基于webkit、V8),
CEF 即 (Chromium Embedder Framework),
是基于Google Chromium项目的开源 Web browser控件(WebView)。

可查看github文档:cefpython api

pip install cefpython3
cefpython3-66.1-py2.py3-none-win_amd64.whl (69.0 MB)
Successfully installed cefpython3-66.1

cd \Python37\Lib\site-packages\cefpython3\examples
copy tkinter_.py  tk_cef.py
用的图片在 \Python37\Lib\site-packages\cefpython3\examples\resources\
编写 tk_cef.py 如下

# -*- coding: utf-8 -*-
# Example of embedding CEF Python browser using Tkinter toolkit.
# This example has two widgets: a navigation bar and a browser.
#
# Tested configurations:
# - Tk 8.5 on Windows/Mac
# - Tk 8.6 on Linux
# - CEF Python v55.3+
#
import ctypes
try:import tkinter as tk
except ImportError:import Tkinter as tk
import sys
import os
import platform
import logging as _logging
from cefpython3 import cefpython as cef
# help(cef.PyBrowser)
# Fix for PyCharm hints warnings
WindowUtils = cef.WindowUtils()# Platforms
WINDOWS = (platform.system() == "Windows")
LINUX = (platform.system() == "Linux")
MAC = (platform.system() == "Darwin")# Globals
logger = _logging.getLogger("tk_cef.py")
baseurl = "http://localhost:8888/"# Constants
# Tk 8.5 doesn't support png images
IMAGE_EXT = ".png" if tk.TkVersion > 8.5 else ".gif"def main():logger.setLevel(_logging.DEBUG)stream_handler = _logging.StreamHandler()formatter = _logging.Formatter("[%(filename)s] %(message)s")stream_handler.setFormatter(formatter)logger.addHandler(stream_handler)logger.info("CEF Python {ver}".format(ver=cef.__version__))logger.info("Python {ver} {arch}".format(ver=platform.python_version(), arch=platform.architecture()[0]))logger.info("Tk {ver}".format(ver=tk.Tcl().eval('info patchlevel')))assert cef.__version__ >= "55.3", "CEF Python v55.3+ required to run this"# 替换python预定义异常处理逻辑,为保证异常发生时能够结束所有进程sys.excepthook = cef.ExceptHook  # To shutdown all CEF processes on error# Tk must be initialized before CEF otherwise fatal error (Issue #306)root = tk.Tk()app = MainFrame(root)settings = {}if MAC:settings["external_message_pump"] = Truecef.Initialize(settings=settings)app.mainloop()logger.debug("Main loop exited")cef.Shutdown() # 结束进程class MainFrame(tk.Frame):""" tk GUI 主界面 """def __init__(self, root):self.browser_frame = Noneself.navigation_bar = Noneself.root = root# Rootroot.geometry("900x640")tk.Grid.rowconfigure(root, 0, weight=1)tk.Grid.columnconfigure(root, 0, weight=1)# MainFrametk.Frame.__init__(self, root)self.master.title("tkinter + cef")self.master.protocol("WM_DELETE_WINDOW", self.on_close)self.master.bind("<Configure>", self.on_root_configure)self.setup_icon()self.bind("<Configure>", self.on_configure)self.bind("<FocusIn>", self.on_focus_in)self.bind("<FocusOut>", self.on_focus_out)# NavigationBarself.navigation_bar = NavigationBar(self)self.navigation_bar.grid(row=0, column=0,sticky=(tk.N + tk.S + tk.E + tk.W))tk.Grid.rowconfigure(self, 0, weight=0)tk.Grid.columnconfigure(self, 0, weight=0)# BrowserFrameself.browser_frame = BrowserFrame(self, self.navigation_bar)self.browser_frame.grid(row=1, column=0,sticky=(tk.N + tk.S + tk.E + tk.W))tk.Grid.rowconfigure(self, 1, weight=1)tk.Grid.columnconfigure(self, 0, weight=1)# Pack MainFrameself.pack(fill=tk.BOTH, expand=tk.YES)def on_root_configure(self, _):#logger.debug("MainFrame.on_root_configure")if self.browser_frame:self.browser_frame.on_root_configure()def on_configure(self, event):logger.debug("MainFrame.on_configure")if self.browser_frame:width = event.widthheight = event.heightif self.navigation_bar:height = height - self.navigation_bar.winfo_height()self.browser_frame.on_mainframe_configure(width, height)def on_focus_in(self, _):logger.debug("MainFrame.on_focus_in")def on_focus_out(self, _):logger.debug("MainFrame.on_focus_out")def on_close(self):if self.browser_frame:self.browser_frame.on_root_close()self.browser_frame = Noneelse:self.master.destroy()def get_browser(self):if self.browser_frame:return self.browser_frame.browserreturn Nonedef get_browser_frame(self):if self.browser_frame:return self.browser_framereturn Nonedef setup_icon(self):resources = os.path.join(os.path.dirname(__file__), "resources")icon_path = os.path.join(resources, "tkinter"+IMAGE_EXT)if os.path.exists(icon_path):self.icon = tk.PhotoImage(file=icon_path)# noinspection PyProtectedMemberself.master.call("wm", "iconphoto", self.master._w, self.icon)class BrowserFrame(tk.Frame):def __init__(self, mainframe, navigation_bar=None):self.navigation_bar = navigation_barself.closing = Falseself.browser = Nonetk.Frame.__init__(self, mainframe)self.mainframe = mainframeself.bind("<FocusIn>", self.on_focus_in)self.bind("<FocusOut>", self.on_focus_out)self.bind("<Configure>", self.on_configure)"""For focus problems see Issue #255 and Issue #535. """self.focus_set()def embed_browser(self):window_info = cef.WindowInfo()rect = [0, 0, self.winfo_width(), self.winfo_height()]window_info.SetAsChild(self.get_window_handle(), rect)global baseurl # 创建浏览器self.browser = cef.CreateBrowserSync(window_info, url=baseurl)assert self.browserself.browser.SetClientHandler(LifespanHandler(self))self.browser.SetClientHandler(LoadHandler(self))self.browser.SetClientHandler(FocusHandler(self))self.message_loop_work()def get_window_handle(self):if self.winfo_id() > 0:return self.winfo_id()else:raise Exception("Couldn't obtain window handle")def message_loop_work(self):""" 消息循环:监听信号和处理事件 """cef.MessageLoopWork()self.after(10, self.message_loop_work)def on_configure(self, _):if not self.browser:self.embed_browser()def on_root_configure(self):# Root <Configure> event will be called when top window is movedif self.browser:self.browser.NotifyMoveOrResizeStarted()def on_mainframe_configure(self, width, height):if self.browser:if WINDOWS:ctypes.windll.user32.SetWindowPos(self.browser.GetWindowHandle(), 0,0, 0, width, height, 0x0002)elif LINUX:self.browser.SetBounds(0, 0, width, height)self.browser.NotifyMoveOrResizeStarted()def on_focus_in(self, _):logger.debug("BrowserFrame.on_focus_in")if self.browser:self.browser.SetFocus(True)def on_focus_out(self, _):logger.debug("BrowserFrame.on_focus_out")"""For focus problems see Issue #255 and Issue #535. """if LINUX and self.browser:self.browser.SetFocus(False)def on_root_close(self):logger.info("BrowserFrame.on_root_close")if self.browser:logger.debug("CloseBrowser")self.browser.CloseBrowser(True)self.clear_browser_references()else:logger.debug("tk.Frame.destroy")self.destroy()def clear_browser_references(self):# Clear browser references that you keep anywhere in your# code. All references must be cleared for CEF to shutdown cleanly.self.browser = Noneclass LifespanHandler(object):def __init__(self, tkFrame):self.tkFrame = tkFramedef OnBeforeClose(self, browser, **_):logger.debug("LifespanHandler.OnBeforeClose")self.tkFrame.quit()class LoadHandler(object):def __init__(self, browser_frame):self.browser_frame = browser_framedef OnLoadStart(self, browser, **_):pass#if self.browser_frame.master.navigation_bar:#   self.browser_frame.master.navigation_bar.set_url(browser.GetUrl())class FocusHandler(object):"""For focus problems see Issue #255 and Issue #535. """def __init__(self, browser_frame):self.browser_frame = browser_framedef OnTakeFocus(self, next_component, **_):logger.debug("FocusHandler.OnTakeFocus, next={next}".format(next=next_component))def OnSetFocus(self, source, **_):logger.debug("FocusHandler.OnSetFocus, source={source}".format(source=source))if LINUX:return Falseelse:return Truedef OnGotFocus(self, **_):logger.debug("FocusHandler.OnGotFocus")if LINUX:self.browser_frame.focus_set()class NavigationBar(tk.Frame):def __init__(self, master):self.back_state = tk.NONEself.forward_state = tk.NONEself.back_image = Noneself.forward_image = Noneself.reload_image = Nonetk.Frame.__init__(self, master)resources = os.path.join(os.path.dirname(__file__), "resources")# Back buttonback_png = os.path.join(resources, "back"+IMAGE_EXT)if os.path.exists(back_png):self.back_image = tk.PhotoImage(file=back_png)self.back_button = tk.Button(self, image=self.back_image,command=self.go_back)self.back_button.grid(row=0, column=0, padx=5, pady=2)# Forward buttonforward_png = os.path.join(resources, "forward"+IMAGE_EXT)if os.path.exists(forward_png):self.forward_image = tk.PhotoImage(file=forward_png)self.forward_button = tk.Button(self, image=self.forward_image,command=self.go_forward)self.forward_button.grid(row=0, column=1, padx=5, pady=2)# Reload buttonreload_png = os.path.join(resources, "reload"+IMAGE_EXT)if os.path.exists(reload_png):self.reload_image = tk.PhotoImage(file=reload_png)self.reload_button = tk.Button(self, image=self.reload_image,command=self.reload)self.reload_button.grid(row=0, column=2, padx=5, pady=2)# Url entryself.url_entry = tk.Entry(self)self.url_entry.bind("<FocusIn>", self.on_url_focus_in)self.url_entry.bind("<FocusOut>", self.on_url_focus_out)self.url_entry.bind("<Return>", self.on_load_url)self.url_entry.bind("<Button-1>", self.on_button1)self.url_entry.grid(row=0, column=3,sticky=(tk.N + tk.S + tk.E + tk.W))tk.Grid.rowconfigure(self, 0, weight=100)tk.Grid.columnconfigure(self, 3, weight=100)# go buttonself.go_button = tk.Button(self, text="go", command=self.go)self.go_button.grid(row=0, column=4, padx=5, pady=2)# prefix button 前缀匹配self.button2 = tk.Button(self, text="prefix", command=self.prefix)self.button2.grid(row=0, column=5, padx=5, pady=2)# Update state of buttonsself.update_state()def go(self):global baseurlurl = self.url_entry.get()if url.strip() =='':returnelif url.startswith("http://"):passelse:url = baseurl + "trans?txt=" + url.strip();if self.master.get_browser():self.master.get_browser().StopLoad()self.master.get_browser().LoadUrl(url)def prefix(self):global baseurlurl = self.url_entry.get()if url.strip() =='':returnelif url.startswith("http://"):if self.master.get_browser():self.master.get_browser().StopLoad()self.master.get_browser().LoadUrl(url)else:url = baseurl + "prefix?txt=" + url.strip();if self.master.get_browser():self.master.get_browser().StopLoad()self.master.get_browser().LoadUrl(url)#self.master.get_browser().ExecuteJavascript(js)def go_back(self):if self.master.get_browser():self.master.get_browser().GoBack()def go_forward(self):if self.master.get_browser():self.master.get_browser().GoForward()def reload(self):if self.master.get_browser():self.master.get_browser().Reload()def set_url(self, url):self.url_entry.delete(0, tk.END)self.url_entry.insert(0, url)def on_url_focus_in(self, _):logger.debug("NavigationBar.on_url_focus_in")def on_url_focus_out(self, _):logger.debug("NavigationBar.on_url_focus_out")def on_load_url(self, _):if self.master.get_browser():self.master.get_browser().StopLoad()self.master.get_browser().LoadUrl(self.url_entry.get())def on_button1(self, _):"""For focus problems see Issue #255 and Issue #535. """logger.debug("NavigationBar.on_button1")self.master.master.focus_force()def update_state(self):browser = self.master.get_browser()if not browser:if self.back_state != tk.DISABLED:self.back_button.config(state=tk.DISABLED)self.back_state = tk.DISABLEDif self.forward_state != tk.DISABLED:self.forward_button.config(state=tk.DISABLED)self.forward_state = tk.DISABLEDself.after(100, self.update_state)returnif browser.CanGoBack():if self.back_state != tk.NORMAL:self.back_button.config(state=tk.NORMAL)self.back_state = tk.NORMALelse:if self.back_state != tk.DISABLED:self.back_button.config(state=tk.DISABLED)self.back_state = tk.DISABLEDif browser.CanGoForward():if self.forward_state != tk.NORMAL:self.forward_button.config(state=tk.NORMAL)self.forward_state = tk.NORMALelse:if self.forward_state != tk.DISABLED:self.forward_button.config(state=tk.DISABLED)self.forward_state = tk.DISABLEDself.after(100, self.update_state)if __name__ == '__main__':main()

这个程序解决了 tkinter 嵌入 cef 后鼠标焦点失控的问题。

cefpython 入门教程 参考: Python GUI: cefpython3的简单分析和应用

web 服务程序:python:mdict + bottle = web 查询英汉词典

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/44943.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TCP编程流程(补充)

目录 1、listen&#xff1a; 2、listen、tcp三次握手 3、 发送缓冲区和接收缓冲区&#xff1a; 4、tcp编程启用多线程 1、listen&#xff1a; 执行listen会创建一个监听队列 listen(sockfd,5) 2、listen、tcp三次握手 三次握手 3、 发送缓冲区和接收缓冲区&#xff1a;…

SpringBoot复习:(52)不再需要使用@EnableTransactionManagement的原因

在Spring项目中&#xff0c;要用事务&#xff0c;需要EnableTransactionManagement注解加Transactional注解。而在SpringBoot项目&#xff0c;有事务的自动配置类TransactionAutoConfiguration,代码如下&#xff1a; 可以在其内部类EnableTransactionManagementConfiguratio…

2017年3月全国计算机等级考试真题(C语言二级)

2017年3月全国计算机等级考试真题&#xff08;C语言二级&#xff09; 第1题 每个学校有一名校长&#xff0c;且不同学校的校长可以是同一人&#xff0c;则实体学校和实体校长间的联系是 A. 多对一 B. 多对多 C. 一对一 D. 一对多 正确答案&#xff1a;A 第2题 若有以下定义…

[JavaWeb]【一】入门JavaWeb开发总概及HTML、CSS、JavaScript

目录 一 特色 二 收获​编辑 三 什么是web? 四 网站的工作流程 五 web网站的开发模式​编辑 六 web开发课程学习安排 七、初始web前端 八 HTML、CSS 8.1 什么是HTNL\CSS(w3cschool) 8.2 HTML快速入门 8.3 VS Code开发工具 8.3.1 插件 8.3.2 主题&#xff08;改变颜色&…

Python写一个创意五子棋游戏

前言 在本教程中&#xff0c;我们将使用Python写一个创意五子棋游戏 &#x1f4dd;个人主页→数据挖掘博主ZTLJQ的主页 个人推荐python学习系列&#xff1a; ☄️爬虫JS逆向系列专栏 - 爬虫逆向教学 ☄️python系列专栏 - 从零开始学python 首先 GomokuGame 类的构造函数 __ini…

Redis、Memcache和MongoDB的区别

>>Memcached Memcached的优点&#xff1a; Memcached可以利用多核优势&#xff0c;单实例吞吐量极高&#xff0c;可以达到几十万QPS&#xff08;取决于key、value的字节大小以及服务器硬件性能&#xff0c;日常环境中QPS高峰大约在4-6w左右&#xff09;。适用于最大程度…

图数据库_Neo4j_Centos7.9安装Neo4j社区版3.5.4_基于jdk1.8---Neo4j图数据库工作笔记0011

首先上传安装包,到opt/soft目录 然后看一下jdk安装的是什么版本的,因为在neo4j 4以后就必须要用jdk11 以上的版本,我这里还用着jdk1.8 所以 我这里用3.5.4的版本 关于下载地址: https://dist.neo4j.org/neo4j-community-3.5.4-unix.tar.gz 然后再去解压到/opt/module目录下 …

【目标检测】目标检测 相关学习笔记

目标检测算法 PASCALVOC2012数据集 挑战赛主要分为 图像分类 目标检测 目标分割 动作识别 数据集分为四个大类 交通&#xff08;飞机 船 公交车 摩托车&#xff09; 住房&#xff08;杯子 椅子 餐桌 沙发&#xff09; 动物&#xff08;鸟 猫 奶牛 狗 马 羊&#xff09; 其他&a…

2023国赛数学建模思路 - 案例:ID3-决策树分类算法

文章目录 0 赛题思路1 算法介绍2 FP树表示法3 构建FP树4 实现代码 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 算法介绍 FP-Tree算法全称是FrequentPattern Tree算法&#xff0c;就是频繁模…

[JavaWeb]【四】web后端开发-SpringBootWeb入门

目录 一 Spring 二 SpringBootWeb入门 2.1 入门需求 2.2 分析 2.3 开始创建SpringBootWeb 2.4 创建类实现需求 2.5 启动程序 2.6 访问 三 HTTP协议 3.1 HTTP-概述 3.2 HTTP-请求协议 3.3 HTTP-响应协议 3.3.1 响应状态码 && 响应类型 3.4 HTTP-协议解析 前言…

八大排序算法 - Java实现

冒泡排序 排序原理&#xff1a; 比较相邻的元素。如果前一个元素比后一个元素大&#xff0c;就交换这两个元素的位置。对每一对相邻元素做同样的工作&#xff0c;从开始第一对元素到结尾的最后一对元素。最终最后位置的元素就是最大值 代码实现&#xff1a; import java.uti…

Liunx系统编程:进程信号的概念及产生方式

目录 一. 进程信号概述 1.1 生活中的信号 1.2 进程信号 1.3 信号的查看 二. 信号发送的本质 三. 信号产生的四种方式 3.1 按键产生信号 3.2 通过系统接口发送信号 3.2.1 kill -- 向指定进程发送信号 3.2.2 raise -- 当自身发送信号 3.2.3 abort -- 向自身发送进程终止…

【ES5和ES6】数组遍历的各种方法集合

一、ES5的方法 1.for循环 let arr [1, 2, 3] for (let i 0; i < arr.length; i) {console.log(arr[i]) } // 1 // 2 // 32.forEach() 特点&#xff1a; 没有返回值&#xff0c;只是针对每个元素调用func三个参数&#xff1a;item, index, arr &#xff1b;当前项&#…

嵌入式Linux开发实操(八):UART串口开发

串口可以说是非常好用的一个接口,它同USB、CAN、I2C、SPI等接口一样,为SOC/MCU构建了丰富的接口功能。那么在嵌入式linux中又是如何搭建和使用UART接口的呢? 一、Console接口即ttyS0 ttyS0通常做为u-boot(bootloader的一种,像是Windows的BIOS),它需要一个交互界面,一般…

HTML中的字符串转义

为什么要转义&#xff1f; 转义可以防止 xss 攻击。接下来&#xff0c;我们来看一下如何转义。 HTML Sanitizer API Sanitizer 是浏览器自带的转义方法&#xff0c;在2021年初被提出&#xff0c;兼容性问题很大。 列举几个常用的 API&#xff1a; const $div document.qu…

C++------利用C++实现二叉搜索树【数据结构】

文章目录 二叉搜索树概念二叉搜索树的操作查找插入删除 二叉搜索树的应用 二叉搜索树 概念 什么是二叉搜索树&#xff0c;二叉搜索树就是指左孩子永远比根小右孩子永远比根大。这个规则适用于所有的子树。 上面的就是一棵二叉搜索树&#xff0c;我们还可以发现这棵树走一个中…

Windows安装 Elasticsearch 教程

下载地址 Past Releases of Elastic Stack Software | Elastic 解压 解压完的样子 进入BIN目录 D:\Develop\elasticsearch\elasticsearch-7.12.0\bin 按住shift 鼠标右键 打开 powershell 窗口 查看ES版本 .\elasticsearch.bat --version 出现问题了 警告&#xff1a;不赞成…

如何学习专业的学术用语01

问题的提出——凭啥人家写的词汇这么专业 做法一 做法二&#xff1a;做一个专业数据库 专门做教育技术类的

React(6)

1.React插槽 import React, { Component } from react import Child from ./compoent/Childexport default class App extends Component {render() {return (<div><Child><div>App下的div</div></Child></div>)} }import React, { Compon…

(二)结构型模式:4、组合模式(Composite Pattern)(C++实例)

目录 1、组合模式&#xff08;Composite Pattern&#xff09;含义 2、组合模式应用场景 3、组合模式的优缺点 4、组合模式的UML图学习 5、C实现组合模式的简单示例&#xff08;公司的OA系统&#xff09; 1、组合模式&#xff08;Composite Pattern&#xff09;含义 组合模…