python - How to run a cancellable function when a new Tkinter window opens -


in tkinter, create following:

when button foo pressed, function foo begins running immediately. new window pop a "cancel" button lets user terminate process midway through (as actual process can take 30 minutes). if foo runs completion, window closes , notifies user process completed.

here code demonstrates toy problem:

from tkinter import ttk, messagebox, toplevel, tk import time import multiprocessing  def foo():     in range(100):         print(i)         time.sleep(0.1)  class terminatedprocess(exception):     def __init__(self, str = "process terminated"):         self.error_str = str  class processwindow(toplevel):     def __init__(self, parent, process):         toplevel.__init__(self, parent)         self.parent = parent         self. process = process          terminate_button = ttk.button(self, text="cancel", command=self.cancel)         terminate_button.grid(row=0, column=0)          self.grab_set() # can't push submit multiple times      def cancel(self):         self.process.terminate()         self.destroy()         raise terminatedprocess      def launch(self):         self.process.start()         self.process.join()         self.destroy()  class mainapplication(ttk.frame):     def __init__(self, parent, *args, **kwargs):         ttk.frame.__init__(self, parent, *args, **kwargs)         self.parent = parent          self.button = ttk.button(self, text = "foo", command = self.callback)         self.button.grid(row = 0, column = 0)      def callback(self):         try:             proc = multiprocessing.process(target=foo)             process_window = processwindow(self, proc)             process_window.launch()         except terminatedprocess e: # raised if foo cancelled in other window             messagebox.showinfo(title="cancelled", message=e.error_str)         else:             messagebox.showinfo(message="sucessful run", title="finished")  def main():     root = tk()     my_app = mainapplication(root, padding=(4))     my_app.grid(column=0, row=0)     root.mainloop()  if __name__ == '__main__':     main() 

with code, when button foo pressed, process_window indeed made because the function foo runs, , "run successful" dialogue box, window never pops up! problem because user needs have option of terminating foo. interestingly enough, if delete process_window.launch(), still "run successful" message (as expected), process_window shows up.

i have tried putting launch command inside initialization, made window not show up, either.

i tried starting process outside window declaration follows:

proc.start() process_window = processwindow(self, proc) proc.join() 

the window still failed show up, process ran.

my question is, how need arrange these pieces generate processwindow , automatically start process when processwindow opens?

update (workaround): aware create start button inside processwindow run function (and disable button after had been pressed once), still know how implement described in original question.

perhaps looking this:

from tkinter import ttk, messagebox, toplevel, tk import time import multiprocessing  def foo():     in range(100):         print(i)         time.sleep(0.1)  class processwindow(toplevel):     def __init__(self, parent, process):         toplevel.__init__(self, parent)         self.parent = parent         self.process = process          terminate_button = ttk.button(self, text="cancel", command=self.cancel)         terminate_button.grid(row=0, column=0)          self.grab_set() # can't push submit multiple times      def cancel(self):         self.process.terminate()         self.destroy()         messagebox.showinfo(title="cancelled", message='process terminated')      def launch(self):         self.process.start()         self.after(10, self.isalive)            # starting loop check when process going end      def isalive(self):         if self.process.is_alive():                     # process still running             self.after(100, self.isalive)               # going again...         elif self:             # process finished             messagebox.showinfo(message="sucessful run", title="finished")             self.destroy()  class mainapplication(ttk.frame):     def __init__(self, parent, *args, **kwargs):         ttk.frame.__init__(self, parent, *args, **kwargs)         self.parent = parent          self.button = ttk.button(self, text = "foo", command = self.callback)         self.button.grid(row = 0, column = 0)      def callback(self):         proc = multiprocessing.process(target=foo)         process_window = processwindow(self, proc)         process_window.launch()  def main():     root = tk()     my_app = mainapplication(root, padding=(4))     my_app.grid(column=0, row=0)     root.mainloop()  if __name__ == '__main__':     main()