Python 如何使用tkinter检查小部件是否是另一个小部件的后代

Python 如何使用tkinter检查小部件是否是另一个小部件的后代,python,python-3.x,tkinter,Python,Python 3.x,Tkinter,我正在创建一个弹出消息,如果用户在弹出框外单击,该消息将消失。要检查用户是否在框架外单击,代码如下所示: import tkinter as tk def build_popup(self, root): popup_frame = tk.Frame(root) popup_frame.grid(row=0, column=0) # binding to check if click is outside the frame self.popup_frame_funcid =

我正在创建一个弹出消息,如果用户在弹出框外单击,该消息将消失。要检查用户是否在框架外单击,代码如下所示:

import tkinter as tk

def build_popup(self, root):
  popup_frame = tk.Frame(root)
  popup_frame.grid(row=0, column=0)

  # binding to check if click is outside the frame
  self.popup_frame_funcid = root.bind_all('<Button-1>', self.delete_popup)

  my_canvas = tk.Canvas(popup_frame, width=200, height=200)
  my_canvas.grid(row=0, column=0)

def delete_popup(self, root, event):
  # if location clicked is not that of a child of the frame destroy popup
  if root.winfo_containing(event.x_root, event.y_root) not in popup_frame.winfo_children():
    popup_frame.destroy()
    root.unbind('<Button-1>', self.popupframe_funcid)
将tkinter作为tk导入
def build_弹出窗口(自身、根):
popup_frame=tk.frame(根)
弹出框架网格(行=0,列=0)
#绑定以检查单击是否在框架外
self.popup\u frame\u funcid=root.bind\u all(“”,self.delete\u弹出窗口)
my_canvas=tk.canvas(弹出框,宽度=200,高度=200)
my_canvas.grid(行=0,列=0)
def delete_弹出窗口(自我、根、事件):
#如果单击的位置不是框架的子对象,则销毁弹出窗口
如果root.winfo_包含(event.x_root,event.y_root)不在弹出框中。winfo_子项():
弹出窗口\u frame.destroy()
root.unbind(“”,self.popupframe_funcid)
然而,当一个小部件被添加到
my_canvas
,例如一个条目,并且它的父项被声明为
my_canvas
时,我遇到了一个问题。当我单击添加的小部件时,
popup\u frame.winfo\u children()
(相当合理)不会将添加的小部件识别为
popup\u frame
的子部件并销毁该框架

tkinter中是否有一个功能,我可以用来检查一个小部件是否是另一个小部件的后代,或者我是否被迫手动跟踪添加到弹出框中的每个小部件


如果有一种更简单/替代的方法来实现相同的结果,我也会很高兴听到它。

您可以使用
winfou\u parent
来获取小部件的父级。然后,您可以在父级和父级的父级上调用该函数,以此类推,以获取小部件的祖先
winfo_parent
返回一个字符串而不是父对象,但是tkinter有一种将名称转换为小部件的方法

例如,要获取名为
w
的小部件的父小部件,可以执行以下操作:

parent = w.nametowidget(w.winfo_parent())
这样,您就可以沿着小部件的层次结构向上移动,在到达根窗口时停止。

我使用
winfo_children()
winfo_parent()
来标识子部件和父小部件/容器。请注意,单个
表示根窗口

import tkinter as tk


class App(tk.Tk):
    def __init__(self):
        super().__init__()
        frame1 = tk.Frame(self)
        btn1 = tk.Button(self)
        btn2 = tk.Button(self)
        btn3 = tk.Button(frame1)

        print('Root children widget are: {}'.format(self.winfo_children()))
        print('frame1 children widget is: {}'.format(frame1.winfo_children()))
        print('Button 1 parent is: {}'.format(btn1.winfo_parent()))
        print('Button 2 parent is: {}'.format(btn2.winfo_parent()))
        print('Button 3 parent is: {}'.format(btn3.winfo_parent()))


if __name__ == '__main__':
    App().mainloop()
结果:


我把事情弄得一团糟,找到了一个替代前面提到的解决方案

str(我的小部件)
返回我的小部件的字符串路径

因此,您可以通过简单地检查
my_canvas
的路径是否以
popup_frame
的路径开始来检查
my_canvas
是否是
popup_frame
的后代

在python中,这很简单:

str(我的画布)。开始使用(str(弹出框))