【 Tkinter界面-练习05】 event和bind

news2025/2/23 2:30:22

一、说明

        事件和动作有关;所有的界面都与运动有关,本篇将对事件、事件触发、绑定回调函数等,其实是一系列部件配合的复杂的过程,这些过程牵扯到系统如何设计,线程、消息队列循环等。本篇将详细介绍各种因素的关系。

二、事件循环

        在上一章的末尾,我们解释了如何使用进度条向用户提供有关长时间运行的反馈 操作。进度条本身很简单:调用其方法,执行操作,然后 调用其方法。不幸的是,您了解到,如果您尝试此操作,您的应用程序将最 可能看起来完全冻结。startstop

        为了理解原因,我们需要在Tk概念一章中重新审视我们对事件处理的讨论。 正如我们所看到的,在我们构造应用程序的初始用户界面之后,它会进入 Tk 事件循环。事件循环 持续处理从系统事件队列中提取的事件,通常每秒数十次。它监视鼠标或键盘事件,根据需要调用命令回调和事件绑定。

        不太明显的是,所有屏幕更新仅在事件循环中处理。例如,您可以更改标注微件的文本。 但是,该更改不会立即显示在屏幕上。相反,小部件会通知 Tk 需要重新绘制。稍后,在处理之间 其他事件,Tk 的事件循环将要求小部件重新绘制自身。所有绘制仅在事件循环中发生。更改似乎发生了 因为更改小部件和事件循环中实际重绘之间的时间太短了。

屏幕截图


显示应用程序回调和屏幕更新的事件循环。

三、阻塞事件循环

        当事件循环长时间无法处理事件时,您会遇到问题。您的应用程序不会重绘 或响应事件,并且看起来被冻结。事件循环被称为阻塞。怎么会这样?

        让我们首先将事件循环可视化为执行时间线。在正常情况下,每次偏离事件循环 (回调、屏幕更新)只需几分之一秒即可将控制权返回到事件循环。

屏幕截图


行为良好的事件循环的执行时间线。

        在我们的场景中,整个事情可能从一个事件开始,比如用户按下 一个按钮。因此,事件循环调用我们的应用程序代码来处理事件。我们的代码创建进度条,执行(冗长的)操作, 并停止进度条。只有这样,我们的代码才会将控制权返回到事件循环。在此期间未处理任何事件,并且未发生屏幕重绘。事件在事件队列中堆积如山。

屏幕截图


冗长的回调阻止事件循环。

        为了防止阻塞事件循环,事件处理程序必须快速执行并将控制权返回到事件循环。

        如果要执行长时间运行的操作或可能需要很长时间的网络 I/O 等操作,则有一些操作 您可以采取不同的方法。

对于技术上更倾向于的人,Tk使用单线程,事件驱动的编程模型。所有 GUI 代码、事件循环和您的 应用程序在同一线程中运行。因此,强烈建议不要进行任何阻止事件处理程序的调用或计算。 某些 GUI 工具包使用不同的模型,这些模型允许阻塞代码,在单独的线程中运行 GUI 和事件处理程序 应用程序代码等试图将这些模型硬塞进 Tk 可能是一个秘诀 挫败感并导致脆弱和黑客的代码。如果你尊重Tk的模式而不是与之抗争,你就不会遇到问题。

四、一步一个脚印

        如果可能的话,你能做的最好的事情就是把你的操作分成几个小步骤,每个步骤都可以非常快速地执行。你让 事件循环负责下一步何时发生。这样,事件循环将继续运行,处理常规事件, 更新屏幕,并在所有这些之间调用代码以执行操作的下一步。

        为此,我们使用计时器事件。我们的程序可以要求事件循环在以后生成其中一个事件。 作为其正常工作的一部分,当事件循环到达该时间时,它将回调我们的代码来处理事件。我们的代码 将执行操作的下一步。然后,它为操作的下一步安排另一个计时器事件,并立即 将控制权返回到事件循环。

屏幕截图


将大型操作分解为与计时器事件绑定在一起的小步骤。

        Tk 的命令可用于生成计时器事件。提供在应触发事件之前等待的毫秒数。 如果 Tk 忙于处理其他事件,则可能会晚发生,但在此之前不会发生。 您还可以要求生成事件;当队列中没有其他事件需要处理时,它将触发。 (Tk 的屏幕更新和重绘发生在空闲事件的上下文中。您可以在 中找到更多详细信息 参考手册。afteridleafter

        在以下示例中,我们将执行一个分为 20 个小步骤的冗长操作。在执行此操作时, 我们将更新进度条并允许用户中断操作。

def start():
    b.configure(text='Stop', command=stop)
    l['text'] = 'Working...'
    global interrupt; interrupt = False
    root.after(1, step)
    
def stop():
    global interrupt; interrupt = True
    
def step(count=0):
    p['value'] = count
    if interrupt:
        result(None)
        return
    root.after(100)  # next step in our operation; don't take too long!
    if count == 20:  # done!
        result(42)
        return
    root.after(1, lambda: step(count+1))
    
def result(answer):
    p['value'] = 0
    b.configure(text='Start!', command=start)
    l['text'] = "Answer: " + str(answer) if answer else "No Answer"
    
f = ttk.Frame(root); f.grid()
b = ttk.Button(f, text="Start!", command=start); b.grid(column=1, row=0, padx=5, pady=5)
l = ttk.Label(f, text="No Answer"); l.grid(column=0, row=0, padx=5, pady=5)
p = ttk.Progressbar(f, orient="horizontal", mode="determinate", maximum=20); 
p.grid(column=0, row=1, padx=5, pady=5)

        Ruby/Tk 提供该类作为 Tk 命令的前端。第一个参数 构造函数是计时器事件的毫秒数,秒是计时器应重复的次数。 Tk 命令的阻塞变体没有一个很好的界面,所以我们改用。

        为了中断该过程,我们设置一个全局变量,并在每次计时器事件触发时检查它。另一种选择是取消待处理的计时器事件。当我们创建计时器事件时,它会返回一个 ID 号来唯一标识待处理的计时器。要取消它,我们可以调用 after_cancel 方法,并向其传递唯一的 id。

您还会注意到,我们使用了 after 的阻塞形式来模拟执行我们的操作。在这种形式中,调用会阻塞,在返回之前等待给定时间,而不是调度事件。它的工作原理与睡眠系统调用相同。

五、异步 I/O

        计时器事件负责分解长时间运行的计算,您知道可以保证每个步骤快速完成,以便 处理程序将返回到事件循环。如果您的操作可能无法快速完成怎么办?当您制作各种品种时,可能会发生这种情况 对操作系统的调用。最常见的是当我们执行某种 I/O 时,无论是编写文件、与数据库通信还是 从远程 Web 服务器检索数据。

        大多数 I/O 调用都在阻塞,因此在操作完成(或失败)之前它们不会返回。我们想要使用的是非阻塞异步 I/O 调用。当您进行异步 I/O 调用时,它会在操作完成之前立即返回。您的代码 可以继续运行,或者在这种情况下,返回到事件循环。稍后,当 I/O 操作完成时,您的程序会收到通知,并且可以 处理 I/O 操作的结果。

        如果这听起来像是将 I/O 视为另一种类型的事件,那么您完全正确。事实上,它也被称为事件驱动的 I/O

在 Tcl 中,异步 I/O 通过命令进行管理,该命令使用与 Tk、计时器等相同的事件循环。 参考手册中有详细说明。它广泛用于Tcl的其他部分,例如 HTTP 包,以及第三方包。fileeevent

在 Python 中,异步 I/O 由模块和其他模块提供 层层叠叠。asyncio

        所有异步应用程序都严重依赖于事件循环。多么方便;特金特有一个很棒的事件循环!不幸 异步事件循环和 Tkinter 事件循环是不一样的。您不能同时运行两者 时间,至少不在同一个线程中(好吧,你可以让一个重复调用另一个,但它非常笨拙和脆弱)。

我的建议:将 Tkinter 保留在主线程中,并在另一个线程中分拆您的 asyncio 事件循环。

        在主线程中运行的应用程序代码可能需要与在其他线程中运行的 asyncio 事件循环进行协调。 您可以调用在 asyncio 事件循环线程中运行的函数(甚至可以从 Tkinter 事件循环中调用,例如,在小部件回调中) 使用 asyncio 方法。要从 asyncio 事件循环调用 Tkinter,请继续阅读。call_soon_threadsafe

六、线程或进程

        有时,将长时间运行的计算分解为每个快速运行的离散部分是不可能的或不切实际的。或者你可能 使用不支持异步操作的库。或者,像Python一样,它不能很好地与Tk的事件循环配合使用。 在这种情况下,为了保持Tk GUI的响应,您需要移动它们 从事件处理程序中取出耗时的操作或库调用,并在其他位置运行它们。线程,甚至其他进程,都可以对此有所帮助。asyncio

        在线程中运行任务、与它们通信等超出了本教程的范围。 但是,您应该注意将 Tk 与线程一起使用有一些限制。 主要规则是,您只能从加载 Tk 的线程进行 Tk 调用。

        Tkinter 在内部竭尽全力,因此您可以通过将它们路由到 主线程(创建 Tk 实例的线程)。它大多有效,但并非总是如此。尽管它尽力做,但我强烈推荐 您可以从单个线程进行所有 Tkinter 调用。

        如果您需要从另一个线程到运行 Tkinter 的线程进行通信,请使其尽可能简单。用于将虚拟事件发布到 Tkinter 事件队列,然后在代码中发布到该事件。event_generatebind

root.event_generate("<<MyOwnEvent>>")

        它可能更加复杂。Tcl/Tk 库可以在有或没有线程支持的情况下构建。 如果应用程序中有多个线程,请确保在线程生成中运行。如果您不确定,请检查 Tcl 变量 ;它应该是 ,而不是 。tcl_platform(threaded)10

>>> tkinter.Tcl().eval('set tcl_platform(threaded)')
% set tcl_platform(threaded)
>> TclTkIp.new._eval('set tcl_platform(threaded)')
Perl> Tkx::eval("set tcl_platform(threaded)")

        大多数人都应该运行线程构建。在Tcl/Tk中创建非线程构建的能力将来可能会消失。 如果您使用的是带有线程代码的非线程化构建,请将此视为应用程序中的错误,而不是使其工作的挑战。

七、嵌套事件处理

        前三种方法是处理长时间运行的操作,同时保持Tk GUI响应的正确方法。他们有什么 Common 是连续处理各种事件的单个事件循环。该事件循环将调用应用程序代码中的事件处理程序, 做他们的事并迅速返回。

        还有另一种方式。在长时间运行的操作中,可以调用事件循环来处理一堆事件。你可以用一个 命令。不会弄乱计时器事件或异步 I/O。相反,你只是洒一些电话 在整个操作过程中。如果您只想保留屏幕重绘而不处理其他事件,甚至还有一个选项()。updateupdateupdate_idletasks

        这种方法非常简单。如果你幸运的话,它可能会起作用。至少在一段时间内。但迟早,你会遇到 试图以这种方式做事的严重困难。某些内容不会更新,事件处理程序没有被调用,事件正在发生 失踪或被解雇,甚至更糟。你会把程序的逻辑翻过来,然后扯掉你的头发,试图让它再次工作。

使用 时,不会将控制权返回给正在运行的事件循环。您正在有效地启动嵌套的新事件循环 在现有的一个中。请记住,事件循环遵循单个执行线程:没有线程,没有协程。如果你不小心,你就会去 最终从事件循环中调用的事件循环...好吧,你明白了。如果你甚至意识到你正在这样做,放松一下 事件循环(每个循环可能有不同的条件来终止它)将是一个有趣的练习。现实与你的心智模型不符 一个简单的事件循环,一次调度一个事件,独立于所有其他事件。这是与Tk模式作斗争的典型例子。 在非常特殊的情况下,可以使其工作。实际上,你是在自找麻烦。不要说你没有被警告...update

屏幕截图


嵌套事件循环...这样疯狂就说谎了。

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

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

相关文章

BCC源码编译和安装

接前一篇文章&#xff1a;BCC源码下载 1. 进入源码根目录 进入到BCC源码根目录。命令及结果如下&#xff1a; $ cd bcc ~/eBPF/BCC/bcc$ ls cmake CONTRIBUTING-SCRIPTS.md docs images libbpf-tools man scripts src CMakeLists.txt …

Matlab论文插图绘制模板第115期—带Latex公式的图

之前的文章中&#xff0c;分享了Matlab带线标记的图&#xff1a; 带阴影标记的图&#xff1a; 带箭头标记的图&#xff1a; 带图形标记的图&#xff1a; 进一步&#xff0c;分享一下带Latex公式的图&#xff0c;先来看一下成品效果&#xff1a; 特别提示&#xff1a;本期内容『…

http1和http2的主要区别

主要有四个方面&#xff1a; 二进制分帧多路复用服务器主动推送头部压缩 将前两点结合来说&#xff0c;首先 二进制分帧 帧&#xff1a;HTTP/2 数据通信的最小单位&#xff1b; 消息&#xff1a;HTTP/2 中&#xff0c;例如在请求和响应等操作中&#xff0c;消息由一个或多个…

赛宁党支部赴延安开展革命旧址学习主题党日活动

为深入学习贯彻新时代中国特色社会主义思想和中共二十大精神&#xff0c;不断提升党支部成员综合素质和业务能力&#xff0c;2023年9月&#xff0c;赛宁公司党支部组织北京、南京、广州等三地部分党员及入党积极分子开展了“革命旧址学习”主题党日活动&#xff0c;深入寻访延安…

TongWeb8下应用忙碌线程监控

问题 &#xff1a; 在系统运行过程中发现TongWeb进程占用CPU过高&#xff0c;需要分析是应用哪里引起的问题。 分析过程(仅限Linux环境)&#xff1a; 1. 通过top命令查看TongWeb的java进程占用的CPU情况。 查看误区&#xff1a;不要以为java进程CPU占到398%就是高&#xff0…

Java基于微信小程序的青少年健康心理科普平台

第一章 简介 青少年心理健康科普平台为用户提供心理医生咨询服务&#xff0c;系统包括微信小程序端和后台。 微信小程序用户可以先进行注册&#xff0c;填写个人的基本信息提交到服务器&#xff0c;服务器把数据保存到数据库。管理员对青少年的信息进行验证后&#xff0c;青少…

面试官:Javscript数组的常用方法有哪些?

&#x1f3ac; 岸边的风&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 一、操作方法 增 push() unshift() splice concat() 删 pop() shift() splice() slice() 改 splice() …

uview组件库的安装

更多的请查看官方文档uView 2.0 - 全面兼容 nvue 的 uni-app 生态框架 - uni-app UI 框架 (uviewui.com) // 如果您的根目录没有package.json文件的话&#xff0c;请先执行如下命令&#xff1a; // npm init -y 安装 npm install uview-ui2.0.36 // 更新 // npm update uvie…

生产数据追溯产线管理看板助力企业实现产品质量追踪

在现代制造业中&#xff0c;企业对于产品质量的追踪和管理变得越来越重要。产品质量的好坏直接关系到企业的声誉和客户满意度。然而&#xff0c;传统的生产管理方式往往无法提供足够的数据和信息来进行全面的质量追踪。生产看板管理系统的出现为企业解决了这一难题。通过实时的…

大模型LLM深入浅出、主打通俗易懂

AI(人工智能)是通过机器来模拟人类认识能力的一种科技能力。AI最核心的能力就是根据给定的输入做出判断或预测。对数据进行分析&#xff0c;从而总结得到研究对象的内在规律。一般通过使用适当的统计、机器学习、深度学习等方法&#xff0c;对收集的大量数据进行计算、分析、汇…

【FAQ】安防监控系统/视频云存储EasyCVR平台安全检查Proxy出现sql injection的漏洞,该如何修改?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。 最近有用户反馈&…

安卓系列机型 框架LSP 安装步骤 支持多机型 LSP框架通用安装步骤【二】

​​​​​​安卓玩机教程---全机型安卓4----安卓12 框架xp edx lsp安装方法【一】 低版本可以参考上个博文了解相关安装方法。 LSP框架优点 简单来说装lsp框架的优点在于可以安装各种模块。包括 但不限于系统优化 加速 游戏开挂等等的模块。大致相当于电脑的扩展油猴 Lspos…

《思维与智慧》简介及投稿邮箱

《思维与智慧》自1982年创刊&#xff0c;经国家新闻出版署批准&#xff0c;由河北省教育厅主管&#xff0c;河北行知文化传媒有限责任公司主办的益智励 志类大众文化期刊。 《思维与智慧》办刊宗旨是&#xff1a;“开发思维&#xff0c;启迪智慧&#xff0c;滋润心灵”&#x…

C# OpenCvSharp Yolov8 Detect 目标检测

效果 项目 代码 using OpenCvSharp; using OpenCvSharp.Dnn; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms;namespace Open…

全球南方《乡村振兴战略下传统村落文化旅游设计》八一新枝——2023学生开学季许少辉瑞博士生辉少许

全球南方《乡村振兴战略下传统村落文化旅游设计》八一新枝——2023学生开学季许少辉瑞博士生辉少许

全能电子地图下载器3.0-下载离线地图瓦片

前言 vue项目要部署到局域网内&#xff0c;不使用在线地图&#xff0c;而是离线地图&#xff0c;寻求了很多的解决方案&#xff0c;最终决定使用离线地图瓦片leaflet.js实现效果&#xff01; 正文 首先需要下载正版的软件&#xff0c;目前我实用的是V3.0版本的&#xff0c;可能…

gateway之断言的使用详解

文章目录 gateway产生的背景&#xff0c;为什么要是用gateway什么是网关gateway 带来的好处功能特征gateway在项目中使用的依赖 什么是断言断言分类内置自定义示例 断言和过滤器的不同 gateway产生的背景&#xff0c;为什么要是用gateway 一个系统会被拆分为多个微服务&#x…

Android OpenGL 做了一个修图(P 图)功能,对标 PS

P 图功能与 OpenGL 玩过 P 图软件的朋友一定对这个功能有所了解,P 图我们可以简单地看做把一个区域的像素按照某一方向进行移动,产生一定形变效果,基于这个原理,我们可以手动实现瘦脸、长腿、瘦腰、大眼、丰胸等等一系列效果,从而达到美颜、美型的目的。 我们将一个区域的…

四轴无人机-飞行控制原理(PID)

控制目标&#xff1a; 1、稳定/平衡 【最核心】&#xff1a;四旋翼微型飞行器的控制就是以地理坐标系为参考&#xff0c;做三维飞行姿态控制。控制目标是使其在 无动作指令时保持稳定悬停状态&#xff0c;有动作指令 时有效完成指定动作。 2、准确 3、快速 4、鲁棒 控制方法…

【李沐深度学习笔记】线性代数实现

课程地址和说明 线性代数实现p2 本系列文章是我学习李沐老师深度学习系列课程的学习笔记&#xff0c;可能会对李沐老师上课没讲到的进行补充。 这节就算之前内容的复习&#xff0c;后面以截图形式呈现 标量由只有一个元素的张量表示 import torch x torch.tensor([3.0]) y …