kdubs
kdubs

Reputation: 1722

tkinter simple dialog - why does cancel get called?

I'm trying to understand why when I click the 'ok' button that the cancel button is also called. I can't find a way to tell if cancel is called by itself or with the ok button. The event always seems to be None when the functions are called so how can you tell them apart?

I've a couple of other posts similar to this, but in that case it seemed like the event was different.

import tkinter as tk
import tkinter.ttk as ttk
import tkinter.simpledialog

class Ask(tk.simpledialog.Dialog):
    def ok(self, event=None):
        print('dbg ok', event)
        return super().ok(self)

    def cancel(self, event=None):
        print('dbg cancel', event)
        return super().cancel(self)

def show_dialog(app):
    dialog = Ask(title="ask", parent=app)

def main():
    app = tk.Tk()

    app.title('Dialog')

    string_button = ttk.Button(app, text='Show', width=25, command=lambda : show_dialog(app))
    string_button.pack()

    exit_button = ttk.Button(app, text='Close', width=25, command=app.destroy)
    exit_button.pack()

    app.mainloop()

main()

Upvotes: 0

Views: 1036

Answers (2)

TheLizzard
TheLizzard

Reputation: 7680

From tkinter's source code (in tkinter/simpledialog.py):

class Dialog(Toplevel):
    ...
    def ok(self, event=None):
        ...
        try:
            self.apply()
        finally:
            self.cancel()
    ...
    def apply(self):
        '''
        This method is called automatically to process the data, *after*
        the dialog is destroyed. By default, it does nothing.
        '''
        pass # override

So when you call super().ok(self) (which should actually be super().ok()), it calls self.cancel which you also defined. But you can just use a variable to determine if the ok/apply was called:

import tkinter as tk
import tkinter.ttk as ttk
import tkinter.simpledialog

class Ask(tk.simpledialog.Dialog):
    def __init__(self, **kwargs):
        self.oked = False
        super().__init__(**kwargs)

    def apply(self):
        self.oked = True
        print(f"[Debug]: Ok")

    def cancel(self, event=None):
        if not self.oked:
            print(f"[Debug]: Cancel {event=}")
        return super().cancel(self)

def show_dialog(app):
    dialog = Ask(title="ask", parent=app)

def main():
    app = tk.Tk()

    app.title("Dialog")

    string_button = ttk.Button(app, text="Show", width=25, command=lambda : show_dialog(app))
    string_button.pack()

    exit_button = ttk.Button(app, text="Close", width=25, command=app.destroy)
    exit_button.pack()

    app.mainloop()

main()

Upvotes: 1

user16519472
user16519472

Reputation:

I think tk.simpledialog.Dialog.ok is what calls its cancel method. You directly ran these functions in your code, so of course this will happen.

Upvotes: 0

Related Questions