I have a GUI that I'm designing using tkinter. I have it built inside a class. The structure that I usually use is to create a frame and pack all my widgets into it. Then when I need to show a different screen, I destroy that frame and call a function that creates a new parent frame and new widgets to pack into it. Here's a simple example to clarify this structure.
import tkinter as tk
class Window():
def __init__(self, master):
self.master = master
self.master.geometry('300x300')
frame = tk.Frame(self.master)
frame.pack()
self.main(frame)
def goto(self, destination, frame):
frame.destroy()
frame = tk.Frame(self.master)
frame.pack()
goto = {
'main': self.main,
'a': self.a,
'b': self.b
}
goto[destination](frame)
def main(self, frame):
tk.Label(frame, text='Main').pack()
tk.Button(frame, text='Goto A', command=lambda: self.goto('a', frame)).pack()
tk.Button(frame, text='Goto B', command=lambda: self.goto('b', frame)).pack()
def a(self, frame):
tk.Label(frame, text='A').pack()
tk.Button(frame, text='Back to Main', command=lambda: self.goto('main', frame)).pack()
def b(self, frame):
tk.Label(frame, text='B').pack()
tk.Button(frame, text='Back to Main', command=lambda: self.goto('main', frame)).pack()
root = tk.Tk()
Window(root)
root.mainloop()
I prefer this structure to Toplevel windows because I've had problems working with them in the past (windows dropping behind other open windows, focus issues, etc). But I really miss how easy Toplevel windows make it to build modules, instead of having all the code in a single script. Is there a way to easily modularize a structure like this without using Toplevel? It would be great for organization and readability. I've tried taking the different 'screen creation' functions and putting them in modules, but I'm getting circular dependency issues.
main.py
import tkinter as tk
import module
class Window():
def __init__(self, master):
self.master = master
self.master.geometry('300x300')
frame = tk.Frame(self.master)
frame.pack()
self.main(frame)
def goto(self, destination, frame):
frame.destroy()
frame = tk.Frame(self.master)
frame.pack()
goto = {
'main': self.main,
'a': module.a,
}
goto[destination](frame)
def main(self, frame):
tk.Label(frame, text='Main').pack()
tk.Button(frame, text='Goto A', command=lambda: self.goto('a', frame)).pack()
root = tk.Tk()
window = Window(root)
root.mainloop()
module.py
import tkinter as tk
import main
def a(frame):
tk.Label(frame, text='A').pack()
tk.Button(frame, text='Back to Main', command=lambda: main.window.goto('main', frame)).pack()
When I click on the button that should take me to the frame built in the module, I get:
AttributeError: partially initialized module 'module' has no attribute 'a' (most likely due to a circular import)