【 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.rhkb.cn/news/140036.html

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

相关文章

flask_apscheduler实现定时推送飞书消息

需求场景&#xff1a; 实现一个flask服务&#xff0c;通过接口控制一个定时任务任务&#xff08;对酒店订房情况进行检查&#xff09;的开启和停止。要求定时任务完成后&#xff0c;可以通过飞书机器人推送任务完成的消息。 展现效果&#xff1a; 启动定时任务 关闭定时任务…

vue项目打包优化

首先第一步通过浏览器看首次加载的问题大小&#xff0c;时间跨度等方面入手 1. Coverage观察 Coverage是chrome开发者工具的一个新功能&#xff0c;从字面意思上可以知道它是可以用来检测代码在网站运行时有哪些js和css是已经在运行&#xff0c;而哪些js和css是还没有用到的&a…

【刷题】2023年第十四届蓝桥杯大赛软件类省赛C/C++大学A组真题

蓝桥杯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…

【算法挨揍日记】day06——1004. 最大连续1的个数 III、1658. 将 x 减到 0 的最小操作数

1004. 最大连续1的个数 III 1004. 最大连续1的个数 III 题目描述&#xff1a; 给定一个二进制数组 nums 和一个整数 k&#xff0c;如果可以翻转最多 k 个 0 &#xff0c;则返回 数组中连续 1 的最大个数 。 解题思路&#xff1a; 首先题目要我们求出的最多翻转k个0后&#x…

2023华为杯数模C题——大规模创新类竞赛评审方案研究

B题——大规模创新类竞赛评审方案研究 思路&#xff1a;采用数据分析等手段改进评分算法性能 完成情况(1-2问已经完成) 代码下载 问题一 在每个评审阶段&#xff0c;作品通常都是随机分发的&#xff0c;每份作品需要多位评委独立评审。为了增加不同评审专家所给成绩之间的可比…

Android ANR日志分析

会造成ANR的场景&#xff1a; Service Timeout&#xff1a;前台服务在20s内未执行完成&#xff0c;后台为200s&#xff1b; BroadcastQueue Timeout&#xff1a;前台广播在10s内未执行完成&#xff0c;后台为60s&#xff1b; ContentProvider Timeout&#xff1a;内容提供者在…

SAP Oracle表空间扩展技术手册

1、DBACOCKPIT下查看表空间 当表空间不足(达到99%)时,需要按以下步骤扩充表空间(每次扩充20000M,20G): (也可以通过DB13,DB02查看表空间) 新浪博客 Tablespace PSAPSR3 is 100% used | SAP Community Oracle是通过增加数据文件的方式来为表空间扩容。为指定表空间增…

BST搜索二叉树

目录 二叉搜索树概念 ​编辑 1 二叉搜索树的构建 2. 二叉搜索树的删除 3二叉搜索树中放入元素 4. 二叉搜索树中元素的删除 5. 二叉搜索树中元素的遍历 6 二叉搜索树中元素的查找 7二叉搜索树的拷贝构造 二叉搜索树概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一…

WeCanStudio工具套件介绍

直接上视频,在超燃的《天马座幻想》的背景音乐下&#xff0c;再次了解一下该工具套件吧。 WeCanStudio开发套件介绍

LeetCode(力扣)96. 不同的二叉搜索树Python

LeetCode96. 不同的二叉搜索树 题目链接代码 题目链接 https://leetcode.cn/problems/unique-binary-search-trees/description/ 代码 class Solution:def numTrees(self, n: int) -> int:dp [0] * (n 1)dp[0] 1for i in range(1, n 1):for j in range(1, i 1):dp[…

基于华为云云耀云服务器L实例开展性能评测|MySQL性能测评

基于华为云云耀云服务器L实例开展性能评测&#xff5c;MySQL性能测评 1. 测试环境介绍2. 测试环境搭建3. 测试工具3.1. mysqlslap3.2. sysbench 1. 测试环境介绍 随着云计算时代的进一步深入&#xff0c;越来越多的中小企业企业与开发者需要一款简单易用、高能高效的云计算基础…

C++核心编程——P45-52继承

继承 继承是面向对象三大特性之一 有些类与类之间存在特殊的关系&#xff0c;例如下图中: 我们发现&#xff0c;定义这些类的时候&#xff0c;下级别的成员除了拥有上一级的共性&#xff0c;还有自己的特性。 这时候我们就可以考虑利用继承的技术&#xff0c;减少重复代码量…

【一、虚拟机vmware安装】

安装虚拟机 下载 官方下载地址&#xff1a;https://www.vmware.com/cn.html 大概流程就是&#xff0c;最重要的事最后一步

【WSN】基于蚁群算法的WSN路由协议(最短路径)消耗节点能量研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【初阶数据结构】二叉树全面知识总结

二叉树详解 树的概念及其结构树的概念树的相关概念树的表示方法孩纸兄弟表示法双亲表示法&#xff08;并查集&#xff09; 树的实际应用 二叉树二叉树的概念二叉树的种类二叉树的性质二叉树的存储结构 二叉树顺序结构的实现堆的概念及结构堆向上、向下调整法堆的插入堆的删除堆…

YOLOv5如何训练自己的数据集

文章目录 前言1、数据标注说明2、定义自己模型文件3、训练模型4、参考文献 前言 本文主要介绍如何利用YOLOv5训练自己的数据集 1、数据标注说明 以生活垃圾数据集为例子 生活垃圾数据集&#xff08;YOLO版&#xff09;点击这里直接下载本文生活垃圾数据集 生活垃圾数据集组成&…

[Linux入门]---初识冯诺依曼体系

文章目录 1.背景知识2.冯诺依曼体系结构 1.背景知识 冯诺依曼&#xff08;John von Neumann&#xff09;&#xff0c;被称为“计算机之父”&#xff0c;确定了计算机的体系结构——即“冯诺依曼结构”&#xff1b;我们常见的计算机&#xff0c;如笔记本。我们不常见的计算机&am…

蓝桥杯每日一题2023.9.23

4961. 整数删除 - AcWing题库 题目描述 分析 注&#xff1a;如果要进行大量的删除操作可以使用链表 动态求最小值使用堆&#xff0c;每次从堆中取出最小值的下标然后在链表中删除 注意long long 代码解释&#xff1a; while(k --){auto t q.top();q.pop();res t.first;i…

经典题记录 字符串相加/相乘

1. LeetCode 415 字符串相加 代码一&#xff1a;代码简短&#xff0c;但需要借助额外的一个string来保存结果&#xff0c;更占用内存。 class Solution { public:string addStrings(string num1, string num2) {string ans"";int size1num1.size();int size2num2.si…

qt 6知识集

1.Use multi-arg instead [clazy-qstring-arg] 存在过个arg&#xff0c;连写形式如下&#xff1a; QString("%1 %2").arg(a).arg(b);QString("%1 %2").arg(a, b); // one less temporary heap allocation详见参考文献[1]。 2.widget运行后正常打开却看不…