背景

最近想简单粗暴的用 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 并没有一种类似 事件冒泡 的机制,从叶子节点的组件开始向上传递。而只有 bindbind_allbind_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 事件在子元素中共享的更多相关文章

  1. LinearLayout的gravity属性以及其子元素的layout_gravity何时有效;RelativeLayout如何调整其子元素位置只能用子元素中的属性来控制,用RelativeLayout中的gravity无法控制!!!

    LinearLayout的gravity属性以及其子元素的layout_gravity何时有效:RelativeLayout如何调整其子元素位置只能用子元素中的属性来控制,用RelativeLayou ...

  2. js将数组中一个或多个字段相同的子元素中合并

    最近js中遇到js将数组中一个或多个字段相同的子元素中合并,相信很多朋友也有遇到,大家可能有多种方法,我在这里记录一个相对简单的方法,当然大家如有其它更好的方法,请提出来大家共同学习. //将经济事项 ...

  3. 【第三篇】学习 android 事件总线androidEventbus之发布事件,子线程中接收

    发送和接收消息的方式类似其他的发送和接收消息的事件总线一样,不同的点或者应该注意的地方: 1,比如在子线程构造方法里面进行实现总线的注册操作: 2,要想子线程中接收消息的功能执行,必须启动线程. 3, ...

  4. 关于自适应屏幕,设置子元素浮动,父div不能包裹子div,子元素中内容溢出的问题。

    设置HTML适应不同分辨率的屏幕. 需求结构如下: HTML结构代码如下(只是其中一条): <body> <div class="content">< ...

  5. Javascript事件模型(二):Javascript事件的父元素和子元素

    DOM事件标准定义了两种事件流,分别是捕获和冒泡.默认情况下,事件使用冒泡事件流,不使用捕获事件流.你可以指定使用捕获事件流,方法是在注册事件时传入useCapture参数,将这个参数设为true. ...

  6. html 子元素和父元素都监听了 click 事件,点击子元素时为何先触发的是父元素的 click 事件?

    先上一段代码,点击子元素时先触发的是父元素的 click 事件 <html> <head> <script type="text/javascript" ...

  7. 父元素a标签的href默认行为以及子元素绑定的click事件的响应之间存在影响

    原文地址 背景 开发过程中遇到问题,简单写个demo 运行环境为Chrome 68 描述一下这个问题,当a标签内部存在嵌套时, 父元素a标签的href默认行为以及子元素绑定的click事件的响应之间存 ...

  8. a标签嵌套href默认行为与子元素click事件存在影响

    2018-08-07 Question about work 开发过程中遇到问题,简单写个demo 运行环境为Chrome 68 描述一下这个问题,当<a>标签内部存在嵌套时, 父元素&l ...

  9. js 利用事件委托解决mousedown中的click

    有一个需求是这样的: 父元素div绑定一个mousedown事件,子元素a绑定一个click事件. 看解构: <div id="nav"> <a href=&qu ...

随机推荐

  1. webpack解析(1)

    webpack是为现代js程序准备的静态模块打包工具 一:关于对webpack的理解 可以将其认为是一个电脑主板,由于使用js作为源码,因而其可以默认编译js代码(别种类型的文件可以依靠loaders ...

  2. [Linux] Linux命令行与Shell脚本编程大全 Part.3

    Shell Shell 是管理命令行的程序(包在内核外的壳) 不同Shell版本演化关系如下,一般Linux中会自动安装Sh和Bash(Bash比Sh好写,Zsh最好用) .bashrc:Bash 的 ...

  3. Linux 操作系统(一)命令&用户&权限

    以下实例均在Centos7下验证 Centos7 查看命令帮助 man xxx 常用命令 ls / cd - #切到上次目录 cd #回家 cat cat f1 f2 cat f1 f2>f3 ...

  4. linux进阶之远程免密登录,动态添加磁盘及个别基础命令

    一. 免密登录(远程连接ssh) ssh IP   #连接登录到其它机 ssh 192.168.10.102 ssh IP "CMD"   #在其它机器上执行命令 yum -y i ...

  5. linux进程间通信-(转自 临水)

    一.进程间通信概述进程通信有如下一些目的:A.数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间B.共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别 ...

  6. centos 7安装freescale交叉编译工具链

    方法1:可以直接下载gcc包,把文件夹放到/usr/local下即可,然后修改PATH环境变量,既可以使用 方法2:可以下载.rpm包,在本地进行安装,下载地址为(http://www.panduod ...

  7. log4j 日志文件(Day_19)

    详细  :   https://www.cnblogs.com/liaojie970/p/7634838.html log4j  日志文件 1 log4j.rootLogger=debug,CONSO ...

  8. python类属性和实例属性的访问

  9. Python将PDF转为TXT

    PDFMiner----python的PDF解析器和分析器 1.官方文档:http://www.unixuser.org/~euske/python/pdfminer/index.html 2.特征 ...

  10. 微信小程序从开发到上线流程

    一.微信小程序从开发到上线流程 注册小程序 1.登录微信公众平台 https://mp.weixin.qq.com 2.在微信公众平台>立即注册>小程序中注册微信小程序 3.在邮箱中激活并 ...