My initial approach is based on the following example:
Best way to structure a tkinter application?
I am trying to create a more complex application involving multiple sub applications each displayed in a separate top level window. All sub applications need to be able to exchange information among each other. Hence, I intend to use class variables in the main application in order to accomplish this requirement.
At the moment I am stuck at one point:
I do not know how to properly implement the destruction of the sub application class instance once it has been created.
The "app_one" window can be opened exactly one time and then it can be properly closed. Of course, if the window is opened a second time an error occurs since only the "Toplevel" window instance has been destroyed, but not the sub application class instance itself.
How do I properly implement the destruction of the sub application class instance upon closing the "Toplevel" window ?
Besides that, I am also very grateful for any other advise on how to improve the structure of my template below in terms of following "Python" as well as "tkinter" best practice paradigms:
import tkinter
import tkinter.filedialog
class main_app(tkinter.Tk):
root = None
var_one = None
sub_app_one_instance = None
sub_app_two_instance = None
sub_app_thr_instance = None
def __init__(self):
super().__init__()
main_app.root = self # <<< in order to be able to refer to root window in other classes
main_app.var_one = 99 # <<< class variables in order to exchange data between main app and sub apps
main_app.sub_app_one_instance = None
main_app.sub_app_two_instance = None
main_app.sub_app_thr_instance = None
self.create_tkinter_interface_main_app()
def create_tkinter_button(self, button_destination, button_text, button_width):
tkinter_button = tkinter.Button(button_destination, text=button_text, width=button_width)
return tkinter_button
def create_tkinter_label(self, label_destination, label_text):
tkinter_label = tkinter.Label(label_destination, text=label_text)
return tkinter_label
def create_tkinter_interface_main_app(self):
frame_main = tkinter.Frame(self)
frame_sub_one = tkinter.Frame(frame_main, bg="red")
frame_sub_two = tkinter.Frame(frame_main, bg="green")
frame_sub_thr = tkinter.Frame(frame_main, bg="blue")
label_app = self.create_tkinter_label(frame_main, "application")
label_one = self.create_tkinter_label(frame_sub_one, "menu one")
label_two = self.create_tkinter_label(frame_sub_two, "menu two")
label_thr = self.create_tkinter_label(frame_sub_thr, "menu thr")
button_one = self.create_tkinter_button(frame_sub_one, "app_one", 20)
button_one.configure(command=self.sub_app_one_open)
button_two = self.create_tkinter_button(frame_sub_one, "app_two", 20)
label_app.pack(side=tkinter.TOP, fill=tkinter.X, expand=tkinter.NO)
frame_sub_one.pack(side=tkinter.LEFT, fill=tkinter.BOTH, expand=tkinter.YES)
frame_sub_two.pack(side=tkinter.LEFT, fill=tkinter.BOTH, expand=tkinter.YES)
frame_sub_thr.pack(side=tkinter.LEFT, fill=tkinter.BOTH, expand=tkinter.YES)
label_one.pack(side=tkinter.TOP, fill=tkinter.NONE, expand=tkinter.NO, padx=10, pady=10)
button_one.pack(side=tkinter.TOP, fill=tkinter.NONE, expand=tkinter.NO, padx=10, pady=10)
button_two.pack(side=tkinter.TOP, fill=tkinter.NONE, expand=tkinter.NO, padx=10, pady=10)
label_two.pack(side=tkinter.TOP, fill=tkinter.NONE, expand=tkinter.NO, padx=10, pady=10)
label_thr.pack(side=tkinter.TOP, fill=tkinter.NONE, expand=tkinter.NO, padx=10, pady=10)
frame_main.pack(fill=tkinter.BOTH, expand=tkinter.TRUE)
def sub_app_one_open(self):
if not main_app.sub_app_one_instance == None:
main_app.sub_app_one_instance.sub_app_one_move_to_front()
return None
else:
main_app.sub_app_one_instance = sub_app_one()
class sub_app_one(main_app): # <<< inherit from main application in order to be able to access class variables
def __init__(self):
self.sub_app_one_toplevel_instance = tkinter.Toplevel(main_app.root)
self.sub_app_one_toplevel_instance.protocol("WM_DELETE_WINDOW", self.sub_app_one_close_toplevel)
print(main_app.var_one) # <<< access information from main app
def sub_app_one_move_to_front(self):
self.sub_app_one_toplevel_instance.attributes("-topmost", 0x01) # <<< set window state
self.sub_app_one_toplevel_instance.attributes("-topmost", 0x00) # <<< reset window state
def sub_app_one_close_toplevel(self):
self.sub_app_one_toplevel_instance.destroy()
self.sub_app_one_toplevel_instance = None
if __name__ == "__main__":
main_app_instance = main_app()
main_app_instance.mainloop()