在 tkinter 中创建消息框时禁用 window 控件

Disable window controls when a messagebox is created in tkinter

在 tkinter 中创建消息框弹出窗口时,有什么方法可以禁用所有 windows 吗?

代码如下:

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()

这里,当消息框弹出时,我不希望用户能够与任何其他 TkToplevel windows 交互,直到该弹出窗口被销毁。

(我尝试使用 messageboxparent 属性,但它只禁用了一个 window。)

有什么方法可以在 tkinter 中实现吗?

如果有人能帮助我就太好了。

我认为不可能阻止与 windows 的所有交互,例如移动它们(除非您使用 .overrideredirect(True) 这将使 window 装饰消失并且寡妇将不再由 window 经理处理。

但是,可以

  1. 防止顶层出现在弹出窗口的顶部

  2. 显示弹出窗口时禁用根 window 和顶层的“关闭”按钮

对于两者,我在 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.[=25 之上=]

对于 2。我使用 window.protocol("WM_DELETE_WINDOW", lambda: quit(window)),当用户单击 window 的关闭按钮时调用 quit(window)。在 quit() 中,我在销毁 window:

之前检查弹出窗口是否打开
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", "Hello world", 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) 如果您不希望用户在显示弹出窗口时能够调整 windows 的大小。

经过几天的试验,终于找到了解决办法。

这里的基本思路是获取window的所有子widget,检查子widget是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 , Tk) or 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()