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

一、说明

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

二、事件循环

        在上一章的末尾,我们解释了如何使用进度条向用户提供有关长时间运行的反馈 操作。进度条本身很简单:调用其方法,执行操作,然后 调用其方法。不幸的是,您了解到,如果您尝试此操作,您的应用程序将最 可能看起来完全冻结。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 = Falseroot.after(1, step)def stop():global interrupt; interrupt = Truedef step(count=0):p['value'] = countif interrupt:result(None)returnroot.after(100)  # next step in our operation; don't take too long!if count == 20:  # done!result(42)returnroot.after(1, lambda: step(count+1))def result(answer):p['value'] = 0b.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.mzph.cn/news/83087.shtml

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

相关文章

vue3创建的官网提示方法

创建: npm create vuelatest 或许会出现提示: 根据官网提示: 意味着我们需要安装或者更新create-vue的版本 后面就可以跟随提示了

【2023年11月第四版教材】第13章《资源管理》(第三部分)

第13章《资源管理》&#xff08;第部分&#xff09; 4 规划资源管理4.1 数据表现★★★4.2 资源管理计划★★★4.2 团队章程★★★ 5 估算活动资源 4 规划资源管理 组过程输入工具和技术输出规划1.规划资源管理1.项目章程2.项目管理计划&#xff08;质量管理计划、范围基准&am…

VOP —— Noise

目录 Turbulent Noise —— 计算1D/3D类型的Noise Anti-Aliased Flow Noise —— 生成抗锯齿噪波 Anti-Aliased Noise —— 生成抗锯齿噪波 Curl Noise —— 创建divergence-free 3D噪波 Curl Noise 2D —— 创建divergence-free 2D噪波 Flow Noise —— 生成1D/3D Perli…

下载安装nvm教程(附带下载切换node.js版本实操)

目录 一、介绍 二、下载 三、安装步骤 四、配置淘宝源 五、测试 六、常用的nvm命令 七、下载切换node版本实操 node版本参考 一、介绍 node版本管理&#xff1a;nvm就是可以切换你的node版本&#xff0c;特别是当node版本过高或者过低时候&#xff0c;就可以用nvm进行…

036:vue导出页面生成pdf文件

第036个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…

GIF动图怎么变成jpg动图?一键分解GIF动画

GIF格式图片怎么转换成jpg格式图片&#xff1f;在日常生活中jpg、png转GIF格式非常的常见&#xff0c;那么gif转换成jpg格式应该怎么操作呢&#xff1f;很简单&#xff0c;给大家分享一款gif动态图片制作&#xff08;https://www.gif.cn/giffenjie&#xff09;工具&#xff0c;…

计算机视觉与深度学习-卷积神经网络-纹理表示卷积神经网络-卷积神经网络-[北邮鲁鹏]

这里写目录标题 参考文章全连接神经网络全连接神经网络的瓶颈全连接神经网络应用场景 卷积神经网络卷积层(CONV)卷积核卷积操作卷积层设计卷积步长(stride)边界填充特征响应图组尺寸计算 激活层池化层(POOL)池化操作定义池化操作作用池化层超参数常见池化操作 全连接层(FC)样本…

算法通关村 | 透彻理解动态规划

1. 斐波那契数列 1&#xff0c;1&#xff0c;2&#xff0c;3&#xff0c;5&#xff0c;8&#xff0c;13&#xff0c;..... f(n) f(n-1) f(n-2) 代码实现 public static int count_2 0;public int fibonacci(int n){if (n < 2){count_2;return n;}int f1 1;int f2 2;i…

【鸽鸽送书第一期】 | 实现可观测性平台的技术要点是什么?文末参与送书哦!

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《粉丝福利》 《C语言进阶篇》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 &#x1f4cb; 前言实现可观测性平台的技术要点是什么&#xff1f;1.兼容全域信号量2.所谓全域信号量有哪些&#x…

基于AI视觉的表面缺陷检测设备优势显著,加速制造业数智化转型

作为生产制造过程中不可缺少的一步&#xff0c;表面缺陷检测广泛应用于工业领域&#xff0c;包括3C电子、芯片半导体、食品医药、木材等行业。但随着智能化进程加快&#xff0c;制造工厂生产线的质量检测压力加剧&#xff0c;传统人工表面缺陷检测已经无法满足当前社会较高的检…

YOLOv8『小目标』检测指南

前言 目前博主课题组在进行物体部件的异常检测项目&#xff0c;项目中需要先使用 YOLOv8 进行目标检测&#xff0c;然后进行图像切割&#xff0c;最后采用 WinCLIP 模型 进行部件异常检测 但是在实际操作过程中出现问题&#xff0c; YOLOv8 模型目标检测在大目标精确度不错&a…

Mybatis深度解析:从起源到现代应用的全景视角

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

Centos7部署单机版MongoDB

目录 Centos7部署单机版MongoDBMongoDB介绍数据模型索引分布式高可用性查询语言驱动和社区用途缺点 下载并解压安装包创建相关文件夹和文件编辑mongod.conf文件启动mongodb创建管理员用户终止MongoDB服务配置自启动服务关闭SELinux编辑自启动服务文件mongodb服务命令 Centos7部…

spark6. 如何设置spark 日志

spark yarn日志全解 一.前言二.开启日志聚合是什么样的2.1 开启日志聚合MapReduce history server2.2 如何开启Spark history server 三.不开启日志聚合是什么样的四.正确使用log4j.properties 一.前言 本文只讲解再yarn 模式下的日志配置。 二.开启日志聚合是什么样的 在ya…

QT-day1

实现华清远见登陆界面 #include "mywnd.h" #include <iostream> #include <QDebug> #include <QPushButton> #include <QLineEdit> #include <QLabel>MyWnd::MyWnd(QWidget *parent): QWidget(parent) {//设置固定窗口大小长400&…

【计算机毕业设计】基于SpringBoot+Vue的小区物业管理系统的设计与实现

博主主页&#xff1a;一季春秋博主简介&#xff1a;专注Java技术领域和毕业设计项目实战、Java、微信小程序、安卓等技术开发&#xff0c;远程调试部署、代码讲解、文档指导、ppt制作等技术指导。主要内容&#xff1a;毕业设计(Java项目、小程序等)、简历模板、学习资料、面试题…

1262. 可被三整除的最大和

1262. 可被三整除的最大和 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;方法一&#xff1a;贪心 正向思维方法二&#xff1a;贪心 逆向思维 参考代码&#xff1a;方法一&#xff1a;贪心 正向思维方法二&#xff1a;贪心 逆向思维 原题链接&#xff1a;…

机器人制作开源方案 | 随叫随到的智能垃圾桶

作者&#xff1a;卢智浩 尹宗岱 胡文珺 付文智 陈星 单位&#xff1a;江汉大学 指导老师&#xff1a;侍中楼 李巍 本作品围绕探索者场景和应用主题&#xff0c;基于当今时代“智能家”的快速发展&#xff0c;智慧生活成为未来的一大发展趋势&#xff0c;因此我们设计了此款可…

【刷题】蓝桥杯

蓝桥杯2023年第十四届省赛真题-平方差 - C语言网 (dotcpp.com) 初步想法&#xff0c;x y2 − z2&#xff08;yz)(y-z) 即xa*b&#xff0c;ayz&#xff0c;by-z 2yab 即ab是2的倍数就好了。 即x存在两个因数之和为偶数就能满足条件。 但时间是&#xff08;r-l&#xff09;*x&am…

【深度学习实验】线性模型(二):使用NumPy实现线性模型:梯度下降法

目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 三、实验内容 0. 导入库 1. 初始化参数 2. 线性模型 linear_model 3. 损失函数loss_function 4. 梯度计算函数compute_gradients 5. 梯度下降函数gradient_descent 6. 调用函数 一、实验介绍 使用Nu…