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

2024-04-28 23:16:05 发布

您现在位置:Python中文网/ 问答频道 /正文

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

有人能给我指一个模态对话的方法吗?我是否需要为此使用windows函数,或者仅使用Tk或Python函数就足够了?

我在google上搜索到的功能组合看起来很神奇,但它们似乎并不像我所期望的那样工作:

focus_set()

grab_set()

transient(parent)

Tags: 方法函数功能脚本应用程序windowsgoogle对话
2条回答

在我的一个项目中,我在父窗口上使用了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

grab_set是制作窗口“应用程序模式”的适当机制。也就是说,它接受来自同一应用程序中所有其他窗口的所有输入(即:同一进程中的其他Tkinter窗口),但它允许您与其他应用程序交互。

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

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

相关问题 更多 >