如何在 tkinter 中创建模态对话框?

新手上路,请多包涵

我有一个运行一些嵌入式 Python 脚本的 MFC 应用程序。我正在尝试使这个嵌入式脚本创建的对话框之一成为模态,但我没有取得太大的成功。

任何人都可以指出制作模态对话框的方法吗?我需要为此使用 Windows 函数还是仅 Tk 或 Python 函数就足够了?

对于我在谷歌上搜索的内容,看起来像以下功能组合应该会产生魔力,但它们似乎并不像我期望的那样工作:

 focus_set()

grab_set()

transient(parent)

原文由 Mac 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
2 个回答

grab_set 是使窗口“应用程序模式”的正确机制。也就是说,它从同一应用程序中的所有其他窗口获取所有输入(即:同一进程中的其他 Tkinter 窗口),但它允许您与其他应用程序交互。

如果您希望对话框是全局模式的,请使用 grab_set_global 。这将接管整个系统的 所有 键盘和鼠标输入。使用此功能时必须格外小心,因为如果您有阻止应用程序释放抓取的错误,您很容易将自己锁在计算机之外。

当我需要这样做时,在开发过程中,我会尝试编写一个防弹故障保护程序,例如一个定时器,它会在固定的时间后释放抓取。

原文由 Bryan Oakley 发布,翻译遵循 CC BY-SA 3.0 许可协议

在我的一个项目中,我在父窗口上使用了 Tcl 窗口管理器属性“-disabled”,该窗口称为(模态)顶层对话框窗口。

不知道您使用 MFC 应用程序显示的哪些窗口是使用 Tcl 创建或使用的,但是如果您的父窗口是基于 Tk 的,您可以这样做:

在 Python 中,只需在顶层窗口的创建方法中调用父窗口:

 MyParentWindow.wm_attributes("-disabled", True)

在你的模态窗口得到你想要的东西后,不要忘记在你的模态窗口中使用回调函数,再次启用你父窗口的输入! (否则您将无法再次与您的父窗口交互!):

 MyParentWindow.wm_attributes("-disabled", False)

一个 Tkinter(Tcl 版本 8.6)Python 示例(在 Windows 10 64 位上测试):

 # Python 3+
import tkinter as tk
from tkinter import ttk

class SampleApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.minsize(300, 100)
        self.button = ttk.Button(self, text="Call toplevel!", command=self.Create_Toplevel)
        self.button.pack(side="top")

    def Create_Toplevel(self):

        # THE CLUE
        self.wm_attributes("-disabled", True)

        # Creating the toplevel dialog
        self.toplevel_dialog = tk.Toplevel(self)
        self.toplevel_dialog.minsize(300, 100)

        # Tell the window manager, this is the child widget.
        # Interesting, if you want to let the child window
        # flash if user clicks onto parent
        self.toplevel_dialog.transient(self)

        # This is watching the window manager close button
        # and uses the same callback function as the other buttons
        # (you can use which ever you want, BUT REMEMBER TO ENABLE
        # THE PARENT WINDOW AGAIN)
        self.toplevel_dialog.protocol("WM_DELETE_WINDOW", self.Close_Toplevel)

        self.toplevel_dialog_label = ttk.Label(self.toplevel_dialog, text='Do you want to enable my parent window again?')
        self.toplevel_dialog_label.pack(side='top')

        self.toplevel_dialog_yes_button = ttk.Button(self.toplevel_dialog, text='Yes', command=self.Close_Toplevel)
        self.toplevel_dialog_yes_button.pack(side='left', fill='x', expand=True)

        self.toplevel_dialog_no_button = ttk.Button(self.toplevel_dialog, text='No')
        self.toplevel_dialog_no_button.pack(side='right', fill='x', expand=True)

    def Close_Toplevel(self):

        # IMPORTANT!
        self.wm_attributes("-disabled", False) # IMPORTANT!

        self.toplevel_dialog.destroy()

        # Possibly not needed, used to focus parent window again
        self.deiconify()

if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()

有关 Tcl 窗口管理器属性的更多信息,请查看 Tcl 文档: https ://wiki.tcl.tk/9457

原文由 JoeyFromCCP 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题