0

I'm using python to create a class object that controls a Tkinter window. My code looks like this:

class MyGui:
    
    def __init__(self):
        
        self.root = tk.Tk()
        self.root.title("My Gui")
        
        return
    
    def makeButton(self, text, on_click_function, should_pack = True):
        """ Makes a button widget """
        
        button = tk.Button(self.root, text=text, command=on_click_function)
    
        if should_pack:
            button.pack()
    
        return button
    
    def start(self):
        
        self.root.mainloop()
        
    def stop(self):
        
        self.root.destroy()
        

I want to be able to start an instance of the class, then stop it like so:

a = MyGui()
a.makeButton('STOP', a.stop)
a.start()
... // OTHER CODE HERE EVENTUALLY // ...

Everything works fine and the window is successfully created on start() and it vanishes when the button is clicked and stop() executes. The issue is that the mainloop continues to run. I have to manually kill the program using Ctrl+C and it shows it being killed at self.tk.mainloop(n).

If I just do all my tkinter code in a normal file rather than a class, everything works the same but the mainloop also stops when I call destroy on root, and the program ends. If I put it in a class, however, mainloop doesn't stop in spite of the window being destroyed.

Why? How can I get it to stop mainloop too? (I can stop the whole program by calling sys.exit, but I want to keep executing non-Gui stuff after I call stop via the button-press).

Elliptica
  • 3,928
  • 3
  • 37
  • 68
  • `self.root.quit()` ? – Joshua Nixon Jul 16 '21 at 14:15
  • Do you want to stop the program from an event (like a button press) or after a set amount of time? – TheLizzard Jul 16 '21 at 14:15
  • Both, actually. I want to be able to push a button and let the mainloop be quit, or to have it quit on its own after a certain amount of time. – Elliptica Jul 16 '21 at 14:16
  • Also code execution stops at `a.start()` and doesn't reach `a.stop()` until the `mainloop` stops – TheLizzard Jul 16 '21 at 14:16
  • Why would code execution stop at start()? It would run start() then keep going, and then hit the stop() command... I used ..//.. to show there would be other code in the middle, but perhaps that's confusing. – Elliptica Jul 16 '21 at 14:18
  • @Elliptica When creating a button inside the class just use `command=self.close`. If you want it to quit on its own after 10 seconds use: `self.root.after(10000, self.close)`. That will schedule a call to `self.close()` after 10000 milliseconds (which is 10 seconds) – TheLizzard Jul 16 '21 at 14:18
  • @theLizzard If I try that, I get `AttributeError: 'MyGui' object has no attribute 'close'`. If I try it on `root`, I get `AttributeError: '_tkinter.tkapp' object has no attribute 'close'`. – Elliptica Jul 16 '21 at 14:20
  • @Elliptica My bad. Instead of `self.close`, it should be `self.stop`. I misread your code :D – TheLizzard Jul 16 '21 at 14:24
  • @theLizzard, yes that is what I do. Perhaps I should just show the button code. I'll update in one sec. – Elliptica Jul 16 '21 at 14:29
  • @Elliptica Move the `a.makeButton('STOP', a.stop)` before the `a.start()`. After you call `a.start()`, nothing will be executed until the window is closed. – TheLizzard Jul 16 '21 at 14:34
  • @TheLizzard, silly me, it's before a.start() in my code but I inserted it wrong here. I've updated the question. – Elliptica Jul 16 '21 at 14:36
  • @Elliptica If you click the button, it should close the window, right? – TheLizzard Jul 16 '21 at 14:39
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/234974/discussion-between-elliptica-and-thelizzard). – Elliptica Jul 16 '21 at 14:40

1 Answers1

0

I figured out I can solve the problem if I put self.root.quit() and self.root.destroy() together in the stop() function, but not if I use them separately (using just destroy closes the window but leaves the mainloop running; using just quit cancels the mainloop but leaves the window open and in a weird state that causes crashing when you try to close it manually).

So the class function actually needs to look like this:

def stop(self):
    
    self.root.quit()
    self.root.destroy()
Elliptica
  • 3,928
  • 3
  • 37
  • 68