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()