首页 > 解决方案 > 当用户在模态窗口外单击时如何响铃?

问题描述

情况很简单。我有一个带有帮助 - 关于菜单的主窗口。单击此菜单项时,将打开一个模式窗口(假设它是一个关于窗口)。我禁用了self.grab_set()主窗口(尽管当您单击主标题栏时模态窗口会闪烁)。到现在为止还挺好。

这是一个问题:当用户在主窗口的模态窗口之外单击时,我真的很喜欢响铃。

这是我能找到的关于grab_set() 的信息,实际上并没有那么多:

我不太清楚如何理解这一点:这是否意味着您可以在模态窗口内的主窗口上处理事件(比如敲响我的钟声)?所以我尝试了这样的事情:

self.bind('<Button-1>', self.bell) Tkinter 回调中的异常:_tkinter.TclError: bad window path name parent.bind('<Button-1>', self.bell) 没有任何反应

那么,如何像在许多其他应用程序中一样在主窗口的模态窗口外单击时发出铃声?

派生问题

我真的很想了解这种神秘的grab_set()方法。

剥离代码:

import tkinter as tk

class About(tk.Toplevel):
    def __init__(self, parent):
        tk.Toplevel.__init__(self, parent)
        self.geometry('200x150')

        #--- OK button
        btn_ok = tk.Button(self, text='OK', command=self.destroy)  # destroy with OK
        btn_ok.pack(side=tk.TOP)
        btn_ok.focus()                                             # destroy with spacebar

        #--- Make window modal
        self.grab_set()                 
        # self.wait_window()              # is this necessary in this case?
        # self.bind('<Button-1>', self.bell) ??? The question

class MenuBar(tk.Menu):
    def __init__(self, parent):
        tk.Menu.__init__(self)
        helpmenu = tk.Menu(self, tearoff=0)
        helpmenu.add_command(label='About', command=lambda: About(parent))
        self.add_cascade(label='Help', menu=helpmenu)

class MainApp():
    def __init__(self, parent):
        parent.configure(background='#000000')
        parent.geometry('800x600')
        menubar = MenuBar(parent)
        parent.configure(menu=menubar)

if __name__ == '__main__':
    root = tk.Tk()
    MainApp(root)
    root.mainloop()

标签: pythonpython-3.xtkinter

解决方案


当您设置一个抓取时,所有按钮点击都将转到带有抓取的窗口。您以捕获任何其他事件的方式捕获它们。在单击按钮的情况下,您可以通过将函数绑定到<1>.

重要的是要知道根窗口或Toplevel窗口上的绑定将应用于该窗口中的所有小部件。例如,self即使您单击“确定”按钮,代码中的绑定也会触发。因此,回调可能只在与事件关联的小部件与顶层相同时才起作用。

例子:

class About(tk.Toplevel):
    def __init__(self, parent):
        ...
        self.bind("<1>", self.capture_click)
        ...
    def capture_click(self, event):
        if event.widget == self:
            <your logic here>

在想知道用户是否点击了窗口外的情况下,可以使用事件对象的坐标与窗口进行比较,看看点击是在窗口内还是在窗口外。

    def on_click(self, event):
        if event.widget == self:
            if (event.x < 0 or event.x > self.winfo_width() or
                event.y < 0 or event.y > self.winfo_height()):
                self.bell()

推荐阅读