Tkinter 吐槽之二:Event 事件在子元素中共享
背景
最近想简单粗暴的用 Python 写一个 GUI 的小程序。因为 Tkinter 是 Python 自带的 GUI 解决方案,为了部署方便,就直接选择了 Tkinter。
本来觉得 GUI 发展这么多年以来,就算功能简陋,但也应该大差不差才对,何况我的需求本就十分简单。但事实上 Tkinter 的简陋仍然超出了我的想象。因此想写几篇文章,记录一下踩到的坑,权当吐槽。
同系列的其它文章:
Tkinter 吐槽之一:多线程与 UI 交互
问题
在一些情况下,Tkinter 原生的组件因为过于简单而无法满足我们的需求,所以可能需要通过 Frame 自定义一些组件,并响应一些事件。
比如,自定义一个带多个信息的可点击的 Frame:
import tkinter as tk
class PersonFrame(tk.Frame):
def __init__(self, master, name, age):
super().__init__(master=master, width=100, borderwidth=2, padx=5)
tk.Label(self, text=name).pack(side=tk.LEFT, fill=tk.X)
tk.Label(self, text=age, foreground='red').pack(side=tk.RIGHT)
self.bind('<Button-1>', self._on_click)
def _on_click(self, _):
print('clicked')
app = tk.Tk()
frame = PersonFrame(app, 'Tom', '27').pack(fill=tk.X)
frame = PersonFrame(app, 'Jerry', '16').pack(fill=tk.X)
app.mainloop()
这个例子看上去一切都很美好,通过自定义 Frame 的方式创建了一个组件,并且绑定了组件的 鼠标单击 事件。
但是经过实际测试发现,只有当鼠标点击在 Frame 的空白位置时,才会触发 on_click 的调用。如果鼠标点在文字上,并不会有任何效果。这说明, bind 操作只对 Frame 本身生效,并不会对覆盖在其上的子元素生效,即使逻辑上存在父子关系。
因此,这个自定义的组件没有办法真正意义上被当作可点击的组件使用。
方案
根本原因,在于 Tkinter 并没有一种类似 事件冒泡 的机制,从叶子节点的组件开始向上传递。而只有 bind,bind_all, bind_class 这三种形式。很显然,这三种形式都是无法满足要求的。
那么思路就演变为,有没有可能把 Frame 及 Frame 的所有子元素,都绑定上同一个事件的方法呢?
def bind_recursively(widget: tk.Misc, event: str, callback: Callable):
"""Binds event recursively with it's all children. So a widget and all
it's children will share one event and callback.
"""
widget.bind(event, callback)
for w in widget.children.values():
bind_recursively(w, event, callback)
这段代码就是采用类似的思路,首先找到 widget 的所有子元素,然后以递归的方式绑定同一个事件的 callback。这样可以保证一个 widget 中的所有子元素都可以响应同样的事件。从而实现在哪里点击都一致的效果。
总结
工程设计其实就是这样,找到一些理论可行的方法,然后通过抽象、封装的方式转换成一个优雅的解决方案。 Tkinter 原生提供的东西非常有限,但是可以借鉴很多其他的思路来进行扩展,从而满足我们的需求。
Tkinter 吐槽之二:Event 事件在子元素中共享的更多相关文章
- LinearLayout的gravity属性以及其子元素的layout_gravity何时有效;RelativeLayout如何调整其子元素位置只能用子元素中的属性来控制,用RelativeLayout中的gravity无法控制!!!
LinearLayout的gravity属性以及其子元素的layout_gravity何时有效:RelativeLayout如何调整其子元素位置只能用子元素中的属性来控制,用RelativeLayou ...
- js将数组中一个或多个字段相同的子元素中合并
最近js中遇到js将数组中一个或多个字段相同的子元素中合并,相信很多朋友也有遇到,大家可能有多种方法,我在这里记录一个相对简单的方法,当然大家如有其它更好的方法,请提出来大家共同学习. //将经济事项 ...
- 【第三篇】学习 android 事件总线androidEventbus之发布事件,子线程中接收
发送和接收消息的方式类似其他的发送和接收消息的事件总线一样,不同的点或者应该注意的地方: 1,比如在子线程构造方法里面进行实现总线的注册操作: 2,要想子线程中接收消息的功能执行,必须启动线程. 3, ...
- 关于自适应屏幕,设置子元素浮动,父div不能包裹子div,子元素中内容溢出的问题。
设置HTML适应不同分辨率的屏幕. 需求结构如下: HTML结构代码如下(只是其中一条): <body> <div class="content">< ...
- Javascript事件模型(二):Javascript事件的父元素和子元素
DOM事件标准定义了两种事件流,分别是捕获和冒泡.默认情况下,事件使用冒泡事件流,不使用捕获事件流.你可以指定使用捕获事件流,方法是在注册事件时传入useCapture参数,将这个参数设为true. ...
- html 子元素和父元素都监听了 click 事件,点击子元素时为何先触发的是父元素的 click 事件?
先上一段代码,点击子元素时先触发的是父元素的 click 事件 <html> <head> <script type="text/javascript" ...
- 父元素a标签的href默认行为以及子元素绑定的click事件的响应之间存在影响
原文地址 背景 开发过程中遇到问题,简单写个demo 运行环境为Chrome 68 描述一下这个问题,当a标签内部存在嵌套时, 父元素a标签的href默认行为以及子元素绑定的click事件的响应之间存 ...
- a标签嵌套href默认行为与子元素click事件存在影响
2018-08-07 Question about work 开发过程中遇到问题,简单写个demo 运行环境为Chrome 68 描述一下这个问题,当<a>标签内部存在嵌套时, 父元素&l ...
- js 利用事件委托解决mousedown中的click
有一个需求是这样的: 父元素div绑定一个mousedown事件,子元素a绑定一个click事件. 看解构: <div id="nav"> <a href=&qu ...
随机推荐
- CentOS7开放端口以及常用的使用命令记录整理
CentOS7与以前常用的CentOS6还是有一些不同之处的,比如在设置开放端口的时候稍许有些不同,常用的iptables命令已经被firewalld代替.这几天正好有在CentOS7系统中玩Seaf ...
- nginx location标签的匹配规则
location的匹配 匹配符 匹配规则 优先级 = 精确匹配 1 ^~ 以某个字符串开头 2 ~ 区分大小写的正则匹配 3 ~* 不区分大小写的正则匹配 4 !~ 区分大小写不匹配的正则 5 !~* ...
- Linux 用户管理_用户相关配置文件详解
linux的用户管理 linux支持多个用户同时使用同一个用户登陆系统,windows在修改组策略的情况下,也可以多个人使用同一个用户登陆. 远程连接Linux的方式:ssh 远程连接windows的 ...
- 1 理解Linux系统的“平均负载”
什么是平均负载 我们知道使用top或uptime可以用来了解系统的负载情况. uptime 2 02:34:03 up 2 days, 20:14, 1 user, load average: 0.6 ...
- 在安装python 第三方库时遇到【WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, st】问题
在命令执行窗输入: pip install Pyinstaller -i http://pypi.douban.com/simple --trusted-host pypi.douban.com (其 ...
- CentOS 6.5新增加硬盘挂载并实现开机自动挂载
Centos7.x请参考:https://www.cnblogs.com/himismad/p/7851548.html 在内网主机Centos 6.5新增一个50G硬盘 (搭建在CAS服务器,直接新 ...
- 常用数据库连接池配置及使用(Day_11)
世上没有从天而降的英雄,只有挺身而出的凡人. --致敬,那些在疫情中为我们挺身而出的人. 运行环境 JDK8 + IntelliJ IDEA 2018.3 优点: 使用连接池的最主要的优点是性能.创 ...
- Jmeter(四十七) - 从入门到精通高级篇 - 分布式压测部署之负载机的设置(详解教程)
1.简介 千呼万唤始出来,这一篇感觉写了好久,总想写的清楚明白简洁,但是还是洋洋洒洒写了好多,希望大家喜欢吧!本来打算将这一篇文章是放在性能测试中讲解和分享的,但是有的童鞋或者小伙伴们私下问的太多了, ...
- [leetcode] 90. 子集 II.md
90. 子集 II 78. 子集题的扩展,其中的元素可能会出现重复了 我们仍沿用78题的代码,稍作改动即可: 此时需要对nums先排个序,方便我们后面跳过选取相同的子集. 跳过选取相同的子集.当选取完 ...
- Linux - fuser 命令
前言 之前连公司堡垒机的时候发现连不上,找运维排查是建立的链接数太多,很多超时链接没有断掉,导致不能再创建链接 此时,需要手动断开用户终端链接,然后百度搜到 fuser 可以断开用户终端链接 命令作用 ...