问题描述
在 tkinter 中创建消息框弹出窗口时,有没有办法禁用所有窗口?
代码如下:
from tkinter import *
from tkinter import messageBox
def show():
messageBox.showinfo("Test Popup","Hello world")
root = Tk()
root.title("Main Window")
root.geometry("500x500")
toplevel = Toplevel(root)
toplevel.title("Toplevel Window")
toplevel.geometry("300x300")
show_button = Button(root,text = "Show popup",command = show)
show_button.place(x = 200,y = 200)
mainloop()
在这里,当消息框弹出时,我不希望用户能够与任何其他 Tk
或 Toplevel
窗口交互,直到该弹出窗口被销毁。
(我尝试使用 parent
的 messageBox
属性,但它只能禁用一个窗口。)
有没有办法在 tkinter 中实现这一点?
如果有人能帮助我就好了。
解决方法
我认为不可能阻止与窗口的所有交互,例如移动它们(除非您使用 .overrideredirect(True)
这将使窗口装饰消失并且寡妇将停止由窗口管理器处理).
但是,可以
-
防止顶层出现在弹出窗口的顶部
-
在显示弹出窗口时禁用根窗口和顶层的“关闭”按钮
对于这两种情况,我在 show()
中使用以下总体思路:
def show():
# modify state of root and toplevel to make them less interactive
# ...
messagebox.showinfo("Test Popup","Hello world",parent=root)
# put root and toplevel back in their normal state
# ...
对于 1. 我在显示弹出窗口之前使用 root.attributes('-topmost',True)
,它从 root
继承此属性,因此将保留在 toplevel
之上。
对于 2. 我使用 window.protocol("WM_DELETE_WINDOW",lambda: quit(window))
,当用户单击窗口的关闭按钮时调用 quit(window)
。在 quit()
中,我在销毁窗口之前检查是否打开了弹出窗口:
def quit(window):
if not popup:
window.destroy()
popup
是一个全局变量,其值在 show()
中发生变化。
完整代码:
import tkinter as tk
from tkinter import messagebox
def quit(window):
if not popup: # destroy the window only if popup is not displayed
window.destroy()
def show():
global popup
popup = True
root.attributes('-topmost',True)
messagebox.showinfo("Test Popup",parent=root)
root.attributes('-topmost',False)
popup = False
root = tk.Tk()
popup = False
root.protocol("WM_DELETE_WINDOW",lambda: quit(root))
root.title("Main Window")
root.geometry("500x500")
toplevel = tk.Toplevel(root)
toplevel.protocol("WM_DELETE_WINDOW",lambda: quit(toplevel))
toplevel.title("Toplevel Window")
show_button = tk.Button(root,text="Show popup",command=show)
show_button.pack()
root.mainloop()
您可能可以在 show()
中添加更多内容,例如.resizable(False,False)
如果您不希望用户在显示弹出窗口时调整窗口大小。
尝试了几天,终于找到了解决方案。
这里的基本思想是获取一个窗口的所有子窗口部件,检查子窗口部件是 Tk
还是 Toplevel
的实例,并将 -disabled
属性应用于它们。
这是实现:
from tkinter import *
from tkinter import messagebox
def disable_windows(window):
for child in window.winfo_children(): # Get all the child widgets of the window
if isinstance(child,Tk) or isinstance(child,Toplevel): # Check if the child is a Tk or Toplevel window so that we can disable them
child.attributes('-disabled',True)
disable_windows(child)
def enable_windows(window):
for child in window.winfo_children(): # Get all the child widgets of the window
if isinstance(child,Toplevel): # Check if the child is a Tk or Toplevel window so that we can enable them
child.attributes('-disabled',False)
enable_windows(child)
def increase_popup_count():
global popup_count
popup_count += 1
if popup_count > 0: # Check if a popup is currently active so that we can disable the windows
disable_windows(root)
else: # Enable the windows if there is no active popup
enable_windows(root)
def decrease_popup_count():
global popup_count
popup_count -= 1
if popup_count > 0: # Check if a popup is currently active so that we can disable the windows
disable_windows(root)
else: # Enable the windows if there is no active popup
enable_windows(root)
def showinfo(title,message): # A custom showinfo funtion
increase_popup_count() # Increase the 'popup_count' when the messagebox shows up
messagebox.showinfo(title,message)
decrease_popup_count() # Decrease the 'popup_count' after the messagebox is destroyed
def show():
showinfo("Test Popup","Hello world")
root = Tk()
root.title("Main Window")
root.geometry("500x500")
popup_count = 0
toplevel = Toplevel(root)
toplevel.title("Toplevel Window")
toplevel.geometry("400x400")
toplevel_2 = Toplevel(toplevel)
toplevel_2.title("Toplevel Window of Another Toplevel")
toplevel_2.geometry("300x300")
show_button = Button(root,text = "Show popup",command = show)
show_button.place(x = 200,y = 200)
mainloop()