【问题标题】:Tkinter TopLevel Destroy not being detected未检测到 Tkinter TopLevel Destroy
【发布时间】:2018-08-08 14:54:10
【问题描述】:

所以我给自己做了一个小项目,我正在尝试制作一个小工具来连接到 OKEX 交易所。现在我正在研究 GUI,我决定使用 Tkinter。经过大量研究等等,我想出了以下内容,但现在我有点卡住了。

我有 2 个类,一个用于主窗口,一个用于登录窗口。但是,主窗口的某些功能依赖于我提交登录详细信息后发生的情况。现在我知道 Toplevel 用于在 Tkinter 中创建其他窗口,并且您通常使用 .destroy() 关闭这些窗口,如果我想在主窗口类中接收此事件,那么我需要使用 Toplevel.protocol( "WM_DELETE_WINDOW", function_name) call ...但这对我不起作用。

如果我使用右上角的十字关闭它会按预期工作,但如果我使用调用 .destroy() 的函数关闭则不会,谁能向我解释为什么这不能按预期工作?也许我错过了什么?

我想在用户(我)输入他们的详细信息后将第一帧中的文本更改为“登录”,但我需要先登录并通过用户对象来包含这些详细信息。

无论如何,这是代码,请帮助我! 有问题的代码是 LoginBox 类中的 myquit 函数,以及 MainBox 类中的 goToLogin 函数 :)

from tkinter import *
from tkinter.ttk import *


class LoginBox:
    def __init__(self, master):  # Master is the frame that is passed in.
        # Create Frame
        self.master = master
        self.master.title('~ Please Login ~')


    def login_function(self):
        user = "xxx"
        secret_key = "yyy"

        print("User - API Key: " + user)
        print("User - Secret Key: " + secret_key)

        # Perhaps check the login ...

        # if it's a success then quit the function
        self.myquit()

    def myquit(self):
        self.master.destroy()


class MainBox:
    def __init__(self, master):

        # Set the root window
        self.master = master
        self.master.geometry("500x500")
        self.master.title("OkBot v0.1")
        self.master.resizable(False, False)

        # Initialize the frames
        self.uiFrame1 = Frame(self.master)  # The Top Layer -- Login Text + Login Button 

        # uiFrame1 Initialize --Login Text + Login Button
        self.ui1_button = Button(self.uiFrame1, text="Login", command=self.goToLogin).grid(row=0, column=3, sticky=E, padx=1)

    # Create Topview for popup , pass in User Object to LoginBox
    def goToLogin(self):
        loginMaster = Toplevel(self.master)
        loginMaster.protocol("WM_DELETE_WINDOW", self.checkLogin)  # This is if they close via X
        loginGUI = LoginBox(loginMaster)

    def checkLogin(self):

        print("This function was called -- The Protocol for destroyed windows works")


# Initialize the objects and start the program
mainWindow = Tk()
myProgram = MainBox(mainWindow)
mainWindow.mainloop()

【问题讨论】:

  • 如果您将代码减少一点,这将有所帮助。如果问题在于ToplevelWM_DELETE_WINDOW,我们不需要更多。此外,您导入了一个名为 User 的东西,这似乎完全没有必要解决这个问题。
  • 我剪掉了一些东西,为此道歉! User 是一个只包含 API 密钥和秘密密钥的类,用于与我的其他包含所有交易功能(买/卖/检查等)的类一起使用。
  • 虽然User 可能是一个简单的类,但它与所提出的问题无关,并且使他人无法通过复制和粘贴来运行您的代码。
  • 我已经简化了代码,以便其他人能够更容易地遵循,我希望〜^__^

标签: python events tkinter destroy toplevel


【解决方案1】:

如果我使用右上角的十字关闭它会按预期工作,但如果我使用调用 .destroy() 的函数关闭则不会,谁能向我解释为什么这不能按预期工作?也许我错过了什么?

loginMaster.protocol("WM_DELETE_WINDOW", self.checkLogin) 只告诉 tkinter 当窗口管理器销毁窗口时该做什么。当您调用某个调用destroy() 的函数时,它不涉及窗口管理器,因此不会调用您的回调。

如果你想在窗口被销毁时发生一些事情,你应该绑定到<Destroy> 事件。

【讨论】:

  • 哦,谢谢!我知道我可以创建事件绑定,但我不知道我可以绑定到 事件。现在我似乎有一个问题,该函数被多次调用,任何线索为什么会发生这种情况?
  • @user10198266:是的。当您绑定到顶级小部件时,该绑定会影响该小部件的每个子级。这是由于 tkinter 的 bind tags 是如何工作的。有很多与绑定标签相关的问题和答案。简单的解决方案是让您的绑定函数检查哪个小部件导致了事件,并且仅当小部件是顶层本身而不是其子级之一时才起作用。
  • @BryanOakley 我建议您在答案中添加有关多个绑定的警告。我掉进了陷阱,如果我没有把 cmets 弄红,我永远不会注意到它。
猜你喜欢
  • 1970-01-01
  • 2016-12-07
  • 2017-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-20
相关资源
最近更新 更多