以编程方式按下工具栏上的“ X”按钮?

时间:2018-11-08 16:44:16

标签: python tkinter protocols

我知道我可以用.拦截按下X按钮,但是我很难弄清楚如何激活此按钮或至少是按下该按钮时触发的协议。 / p>

这是情况。我有2节课。我的主要protocol("WM_DELETE_WINDOW", do_something)类和我的Tk类。当我通过菜单中的Menu按钮设置关闭程序的命令时,我希望该按钮执行与exit类上的X按钮完全相同的操作。 / p>

现在,我知道我可以简单地调用传递给菜单类的控制器,然后调用我为处理关闭事件而构建的方法,但是我试图以不需要这样的方式构建此菜单类从菜单类中执行此操作。这样,我几乎无需编辑就可以在自己构建的任何应用程序上使用菜单类。

我找不到能告诉我如何以编程方式激活Tk协议的帖子或文档。

这是一张图像,如果不清楚我想要什么。我只是想让退出按钮完全执行"WM_DELETE_WINDOW"按钮的作用。

enter image description here

主类:

X

单独的import tkinter as tk import PIP_MENU class PIP(tk.Tk): def __init__(self): super().__init__() PIP_MENU.start(self) self.protocol("WM_DELETE_WINDOW", self.handle_close) def handle_close(self): print("Closing") self.quit() if __name__ == '__main__': PIP().mainloop() 文件上的菜单类:

.py

3 个答案:

答案 0 :(得分:3)

  

我找不到能告诉我如何以编程方式激活“ WM_DELETE_WINDOW”协议的帖子或文档。

不能。根据定义,WM_DELETE_WINDOW协议来自窗口管理器。

捕获协议处理程序旨在为您提供覆盖其行为的机会。不管应用程序如何销毁,它都不是触发某些代码的方法。如果要在销毁窗口时运行某些代码,无论是通过用户单击窗口框架上的控件还是通过其他方式,执行此操作的正确方法是绑定到窗口上的<Destroy>事件根窗口。

您必须小心,因为将为每个小部件触发根窗口上的任何绑定。因此,绑定仅应在event.widget与根窗口相同时运行。

以下示例说明了该技术。有一种handle_close方法,只要销毁窗口就被调用。无论是通过单击窗口框架上的控件来关闭窗口,还是单击“关闭我!”按钮,代码仍然运行。

import tkinter as tk


class Example(tk.Tk):
    def __init__(self):
        super().__init__()
        self.bind("<Destroy>", self.handle_close)

        button = tk.Button(self, text="Close me!", command=self.destroy)
        button.pack()

    def handle_close(self, event):
        if event.widget == self:
            print("Closing")
        self.quit()

example = Example()
example.mainloop()

答案 1 :(得分:1)

我不相信有一种方法可以调用特定的protocol,因为protocol似乎是特定的事件监视程序。这是模块类Tk的摘录:

class Tk(Misc, Wm):
    """Toplevel widget of Tk which represents mostly the main window
    of an application. It has an associated Tcl interpreter."""

    def _loadtk(self):

    ...

    self.protocol("WM_DELETE_WINDOW", self.destroy)

如您所见,默认情况下,模块本身将协议设置为destroy()protocol()方法仅尝试替换默认功能(在没有功能的情况下,它将删除该功能):

def wm_protocol(self, name=None, func=None):
    """Bind function FUNC to command NAME for this widget.
    Return the function bound to NAME if None is given. NAME could be
    e.g. "WM_SAVE_YOURSELF" or "WM_DELETE_WINDOW"."""
    if callable(func):
        command = self._register(func)
    else:
        command = func
    return self.tk.call(
        'wm', 'protocol', self._w, name, command)
protocol = wm_protocol

但是要实现您想要的功能,您应该可以使用以下方法引用相同的处理方法:

def handle_exit(self):
    self.controller.handle_close()

当然,这并不是通用的,因为您必须在主窗口中明确了解处理程序。

答案 2 :(得分:1)

以为我已经接受了布莱恩(Bryan)的回答,因此设法设法解决了一个我认为很好的解决方法。

如果我将用于关闭窗口的方法传递给菜单类,然后检查是否传递了某些东西,则可以决定天气是否使用我制作的退出方法或self.controller.destroy()带有if语句。

这是我的解决方法。

主文件:

import tkinter as tk
from tkinter import messagebox
import PIP_MENU


class PIP(tk.Tk):
    def __init__(self):
        super().__init__()
        PIP_MENU.start(self, self.handle_close)
        self.protocol("WM_DELETE_WINDOW", self.handle_close)

    def handle_close(self):
        x = messagebox.askquestion("DERP", "Do you want to close without saving?")
        if x == "yes":
            self.destroy()

if __name__ == '__main__':
    PIP().mainloop()

菜单文件:

import tkinter as tk

class Menu(tk.Menu):
    def __init__(self, controller, exit_handler=None):
        super().__init__()
        self.controller = controller
        self.exit_handler = exit_handler
        controller.config(menu=self)
        file_menu = tk.Menu(self, tearoff=0)
        self.add_cascade(label="File", menu=file_menu)
        file_menu.add_command(label="Exit", command=self.handle_exit)

    def handle_exit(self):
        if self.exit_handler != None:
            self.exit_handler()
        else:
            self.controller.quit()


def start(controller, exit_handler=None):
    return Menu(controller, exit_handler)