Tk是否有一个明确的属性,我可以检查它是否mainloop已经停止运行,或者根窗口是否已经被破坏?
下面的最小代码显示了一个由Tks传播python异常的明显失败引起的问题。要查看实际问题,请单击根窗口按钮,启动子窗口对话框。接下来,使用close window按钮(红色X)关闭根窗口。
import sys
import tkinter as tk
class ProgramIsEnding(Exception):
pass
class UnrecognizedButtonException(Exception):
pass
class MainWindow(tk.Tk):
def __init__(self):
super().__init__()
self.title('Root Window')
button = tk.Button(text='Start The Child Window Dialog')
button.configure(command=self.run_dialog)
button.grid()
self.protocol('WM_DELETE_WINDOW', self.delete_window_callback)
def delete_window_callback(self):
self.destroy()
print('Root has been destroyed')
raise ProgramIsEnding
def run_dialog(self):
try:
button = YesNoDialog(self)()
except ProgramIsEnding:
print('Doing end of program stuff.')
return
print(f"Button returned is '{button}'")
if button == 'yes':
print("'Yes' button clicked")
elif button == 'no':
print("'No' button clicked")
else:
msg = f"button '{button}'"
raise UnrecognizedButtonException(msg)
class YesNoDialog:
window: tk.Toplevel = None
button_clicked = None
def __init__(self, parent):
self.parent = parent
def __call__(self):
self.create_window()
return self.button_clicked
def create_window(self):
self.window = tk.Toplevel(self.parent)
yes = tk.Button(self.window, text='Yes', command=self.yes_command)
yes.pack(side='left')
no = tk.Button(self.window, text='No', command=self.no_command)
no.pack(side='left')
self.window.wait_window()
def yes_command(self):
self.button_clicked = 'yes'
self.window.destroy()
def no_command(self):
self.button_clicked = 'no'
self.window.destroy()
def main():
tkroot = MainWindow()
tkroot.mainloop()
if __name__ == '__main__':
sys.exit(main())
如果代码按预期工作,它将在捕获异常后正确终止,即ProgramIsEnding。相反,程序会以未处理的未识别ButtonException终止。下面是完整的错误消息。请注意,尽管try/except处理程序在从Tk将控制权交还给python之后无法使用programmisending异常,但还是通过stdout报告了该异常。
Root has been destroyed
Exception in Tkinter callback
Traceback (most recent call last):
File "[â¦]/python3.7/tkinter/__init__.py", line 1702, in __call__
return self.func(*args)
File "[â¦]/wmdeletedemo.py", line 25, in delete_window_callback
raise ProgramIsEnding
ProgramIsEnding
Exception in Tkinter callback
Traceback (most recent call last):
File "[â¦]/python3.7/tkinter/__init__.py", line 1702, in __call__
return self.func(*args)
File "[â¦]/wmdeletedemo.py", line 41, in run_dialog
raise UnrecognizedButtonException(msg)
UnrecognizedButtonException: button 'None'
Button returned is 'None'
一个明显的解决方法是检查按钮值是否为None,如果是,则返回。不过,对我来说,良好的实践建议我应该检查主要事件,既不依赖其次要效果,也不依赖于设置标志。
那么,Tk或tkinter是否还有其他属性记录mainloop的结束,或者根窗口是否已被破坏?