简体   繁体   中英

Can't make truly modal dialog box in tkinter

I have created a custom dialog box as follows:

class DialogOkCancel(Toplevel):
    """DialogOk Displays a simple 'ok' dialog"""

    def __init__(
        self,
        text: str = "",
        width: int = 300,
        height: int = 200,
        *args,
        **kwargs,
    ):
        super().__init__(title=c.DEFAULT_TITLE)

        self.text = text
        self.width = width
        self.height = height

    def show(self) -> None:

        xpos = (self.winfo_screenwidth() / 2) - (self.width / 2)
        ypos = (self.winfo_screenheight() / 2) - (self.height / 2) - 300
        self.geometry(f"{int(self.width)}x{int(self.height)}+{int(xpos)}+{int(ypos)}")
        self.resizable(False, False)

        self.grid_rowconfigure(index=0, weight=0)
        self.grid_rowconfigure(index=1, weight=0)
        self.grid_columnconfigure(index=0, weight=1)
        self.grid_columnconfigure(index=1, weight=1)

        default_font = font.nametofont("TkDefaultFont")
        default_font.configure(family=c.DEFAULT_FONT_FAMILY)
        default_font.configure(size=c.DEFAULT_FONT_SIZE)

        self.choice = None

        self.text = Label(self, text=self.text, font=default_font, anchor="center")
        self.text.grid(
            row=0, column=0, columnspan=2, padx=(10, 0), pady=(10, 0), sticky="nswe"
        )

        button1 = Button(self, text="Ok", bootstyle="dark", command=self.ok)
        button1.grid(row=1, column=0, padx=(10, 0), pady=(10, 10), sticky="nswe")

        button2 = Button(self, text="Cancel", bootstyle="dark", command=self.cancel)
        button2.grid(row=1, column=1, padx=(10, 10), pady=(10, 10), sticky="nswe")

        self.protocol("WM_DELETE_WINDOW", self.cancel)
        self.wait_visibility()
        self.grab_set()

        self.master.wait_window(self)
        return self.choice

    def ok(self):
        self.choice = True
        self.grab_release()
        self.destroy()

    def cancel(self):
        self.choice = None
        self.grab_release()
        self.destroy()

I have bound the command-q,window close and quit menu option to it as follows:

root.createcommand("tk::mac::Quit", app_quit)
root.protocol("WM_DELETE_WINDOW", app_quit)
root.bind("<Command-q>", app_quit)

The handler is as follows:

def app_quit(*args, **kwargs) -> None:

    dialog = DialogOkCancel(
        f"Are you sure you want to quit?\nThe current game will be saved.",
        height=110,
        width=350,
    )
    ans = dialog.show()

    if ans is True:
        sys.exit()

When i press command-q, close the window or select the quit menu option, the dialog is shown correctly and no further input is allowed in the program.

My problem is that if I press command-q again, or try to close the window again, or select quit from the menu option, then i get multiple copies of the dialog.

Any suggests how to prevent this would be much appreciated. thanks

Thank you Bryan, I have done this:

 def app_quit(self, *args, **kwargs) -> None:

        if self.dialog is None:
            self.dialog = DialogOkCancel(
                f"Are you sure you want to quit?\nThe current game will be saved.",
                height=110,
                width=350,
            )
            ans = self.dialog.show()

            if ans is True:
                self.game.script.save_script(self.game.script.filename)
                sys.exit()

            self.dialog = None

And that works, thanks.

However, while the main interface is blocked, the app menus still work and allow user interaction. Not ideal.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM