Quit Tkinter application by calling class method

69 Views Asked by At

I am trying to build a splash screen that I will be able to call from an external application using Tkinter. I'd like to define my GUI in a class, like this:

class Splash:  
    def __init__(self):  
        self.root = tk.Tk()  
        self.root.overrideredirect(True)  
        self.root.wm_attributes("-topmost", True)
        self.label = tk.Label(self.root, text="Initializing...")  
        self.label.pack(side=tk.BOTTOM)  
        self.progbar = ttk.Progressbar(self.root, orient=tk.HORIZONTAL, mode='indeterminate')  
        self.progbar.pack(fill=tk.BOTH, side=tk.BOTTOM, padx=10)  
        self.progbar.start(40)  
          
        self.root.update_idletasks()  
        self.root.geometry(  
            "+{}+{}".format(  
                int((self.root.winfo_screenwidth() - self.root.winfo_reqwidth()) / 2),  
                int((self.root.winfo_screenheight() - self.root.winfo_reqheight()) / 2),  
            )
        )
        root.mainloop()
        
    def close(self):  
        self.root.destroy()

The goal is that in my external app, I can create a Splash object, run my initialization, and then call the close function on the Splash object to close the splash screen, like this:

import time  
import Splash  

x = Splash.Splash()
time.sleep(5) # App initialization happens here.
x.close()

This isn't working, as root.mainloop() blocks, and the initialization functions are never actually reached. This variation also does not work:

class Splash:  
    closeRequest = False

    def __init__(self):
        
        # Everything up until root.mainloop(), as shown above, goes here
        
        while not self.closeRequest:  
            self.root.update_idletasks()  
            self.root.update()
    
    def close(self):  
        self.closeRequest = True

How can I accomplish my goal here? I'd prefer not to use threads for this, but please feel free to share threads-based solutions as well.

1

There are 1 best solutions below

0
On

If you want a separate Splash.py and main.py files you can do this:

Splash.py

import tkinter as tk
from tkinter import ttk

class Splash:  
    def __init__(self):  
        self.root = tk.Tk()  
        self.root.overrideredirect(True)  
        self.root.wm_attributes("-topmost", True)
        self.label = tk.Label(self.root, text="Initializing...")  
        self.label.pack(side=tk.BOTTOM)  
        self.progbar = ttk.Progressbar(self.root, orient=tk.HORIZONTAL, mode='indeterminate')  
        self.progbar.pack(fill=tk.BOTH, side=tk.BOTTOM, padx=10)  
        self.progbar.start(40)  
          
        self.root.update_idletasks()  
        self.root.geometry(  
            "+{}+{}".format(  
                int((self.root.winfo_screenwidth() - self.root.winfo_reqwidth()) / 2),  
                int((self.root.winfo_screenheight() - self.root.winfo_reqheight()) / 2),  
            )
        )
        #root.mainloop()
        
    def close(self):  
        self.root.withdraw()

main.py

import tkinter as tk
from Splash import Splash

def mainWindow(x):
    x.close()
    mainwindow=tk.Tk()
    mainwindow.title("Calculator")
    mainwindow.geometry('480x240')
    buttonOne = tk.Button(mainwindow,text='1')
    
x = Splash()
x.root.after(5000, lambda: mainWindow(x))
tk.mainloop()

Note that the class Splash doesn't execute root.mainloop() and I use self.root.withdraw() to close the splash screen.

You can have whatever tkinter code you like in the def mainWindow() function which closes the splash screen and starts another screen.