SendingSonGY 发表于 2024-9-9 12:57

tkinter创建子组件后,导致父组件的关闭事件被触发时,连续执行了两次事件函数

本帖最后由 SendingSonGY 于 2024-9-9 13:09 编辑

就不附图了,我写了伪代码。敬请各位大佬帮帮:dizzy:小弟,问了ai,ai也不懂:'(weeqw,大佬们快来呀。

冰茶荼 发表于 2024-9-9 14:01

本帖最后由 冰茶荼 于 2024-9-9 14:27 编辑

不懂py 但是从代码来看 label 组件也触发了销毁事件 看看是否可以在销毁事件中判断来源
https://s21.ax1x.com/2024/09/09/pAmC1gI.png


https://s21.ax1x.com/2024/09/09/pAmPGW9.png

https://s21.ax1x.com/2024/09/09/pAmPJzR.png



经过尝试 给出以下2个解决方案:
方案1:

import threading
import time

import tkinter


win = tkinter.Tk()
win.width = 200
win.height = 200

def a():
    top = tkinter.Toplevel(win)
    top.pack_slaves()

    def x():

      # 这是子组件,不添加这个子组件时,关闭top窗口只print一次。但是添加时,就会print两次。不pack也会。不使用子线程也会。目前排除线程问题。
      la = tkinter.Label(top,text='出现')
      la.pack()
      def b():
            # 使用 top.unbind 来取消剩余事件的触发(触发事件的event不一定是top 是最后一个被添加的组件)
            top.unbind('<Destroy>')
      top.bind('<Destroy>',b)
    t = threading.Thread(target=x)
    t.start()
btn = tkinter.Button(win,text='点我',command=a)
btn.pack()
win.mainloop()


方案2:
import threading
import time

import tkinter


win = tkinter.Tk()
win.width = 200
win.height = 200

def a():
    top = tkinter.Toplevel(win)
    top.pack_slaves()

    def x():

      # 这是子组件,不添加这个子组件时,关闭top窗口只print一次。但是添加时,就会print两次。不pack也会。不使用子线程也会。目前排除线程问题。
      la = tkinter.Label(top,text='出现')
      la.pack()
      def b():
            top.destroy()
      # 使用窗口关闭协议通信
      top.protocol("WM_DELETE_WINDOW", b)
    t = threading.Thread(target=x)
    t.start()
btn = tkinter.Button(win,text='点我',command=a)
btn.pack()
win.mainloop()


冰茶荼 发表于 2024-9-9 13:31

搞个网盘吧 下载附件还得掏钱

SendingSonGY 发表于 2024-9-9 13:40

冰茶荼 发表于 2024-9-9 13:31
搞个网盘吧 下载附件还得掏钱

啊?这个还要钱啊{:1_907:}

Clarkchaoren 发表于 2024-9-9 13:43

我下载了代码,然后直接运行。打开主窗口,又打开子窗口,关闭子窗口,print一次,关闭主窗口没有print。我又运行程序,打开主窗口,然后直接关闭主窗口,没有print,直接退出了。我没有测试到楼主所说的问题。可能python版本不一样。我贴出我运行的截图。

SendingSonGY 发表于 2024-9-9 13:47

Clarkchaoren 发表于 2024-9-9 13:43
我下载了代码,然后直接运行。打开主窗口,又打开子窗口,关闭子窗口,print一次,关闭主窗口没有print。我 ...

代码您看没,我是把子组件的创建注释掉了的

SendingSonGY 发表于 2024-9-9 15:01

冰茶荼 发表于 2024-9-9 14:01
不懂py 但是从代码来看 label 组件也触发了销毁事件 看看是否可以在销毁事件中判断来源




谢谢大佬,确实是这样,您真帅。看了您的阐释以及给出的方案,我很高兴,不仅仅是因为我的问题得到了解决,更是我学到了一些新知识点,比如event.widget,我从来没试过event下的属性和方法,这个属性在此处的调试真的一眼就点醒我了。但是我还是不太理解为什么父组件绑定的destory事件函数会被子组件的destory触发

冰茶荼 发表于 2024-9-9 15:08

SendingSonGY 发表于 2024-9-9 15:01
谢谢大佬,确实是这样,您真帅。看了您的阐释以及给出的方案,我很高兴,不仅仅是因为我的问题得到了解决 ...

因为你创建子组件的时候 target填写的是top,你又监听了top下的销毁,当top窗口被销毁的时候,下面的所有子组件都会触发销毁回调,我的理解是这样的

SendingSonGY 发表于 2024-9-9 15:34

冰茶荼 发表于 2024-9-9 15:08
因为你创建子组件的时候 target填写的是top,你又监听了top下的销毁,当top窗口被销毁的时候,下面的所有 ...

import threading
import time

import tkinter


win = tkinter.Tk()
win.width = 200
win.height = 200

def a():
    top = tkinter.Toplevel(win)
    top.pack_slaves()

    def x():
      la = tkinter.Label(top,text='出现了')
      la.pack()

      def b(e):
            if e.widget == top:
                for w in win.children.values():
                  w.pack_forget()

      top.bind('<Destroy>',b)


    t = threading.Thread(target=x)
    t.start()


btn = tkinter.Button(win,text='点我',command=a)
btn.pack()
win.mainloop()
                                          大佬您再帮我看看这个错误呗,我在destory事件函数中写了隐藏所有win的子组件,但是top窗口也被算在内了,此时top窗口难道不是已经被销毁了吗?

冰茶荼 发表于 2024-9-9 15:51

SendingSonGY 发表于 2024-9-9 15:34
import threading
import time



b触发的时候top窗口应该还没有销毁
页: [1]
查看完整版本: tkinter创建子组件后,导致父组件的关闭事件被触发时,连续执行了两次事件函数