I am trying to create simple app with multiple screens. Here is my project structure.
main.py
- screens
mainScreen.py
regressions.py
What i want to do is basically switch between them which i cant because of ImportError: cannot import name 'MainScreen' from partially initialized module 'screens.mainScreen' (most likely due to a circular import)
I think i understand what problem is but i dont know how to overcome it.
Here is my code
main.py
import tkinter as tk
from screens.mainScreen import MainScreen
root = tk.Tk()
run = MainScreen(root)
root.mainloop()
regressions.py
import tkinter as tk
from .mainScreen import MainScreen
class Regressions:
def __init__(self, master):
# keep `root` in `self.master`
self.master = master
self.label = tk.Button(self.master, text="Home", command=self.load_new)
self.label.pack()
def load_new(self):
self.label.destroy()
# use `root` with another class
self.another = MainScreen(self.master)
mainScreen.py
import tkinter as tk
from .regressions import Regressions
class MainScreen:
def __init__(self, master):
# keep `root` in `self.master`
self.master = master
self.label = tk.Button(self.master, text="Regressions", command=self.load_new)
self.label.pack()
def load_new(self):
self.label.destroy()
# use `root` with another class
self.another = Regressions(self.master)
mainScreen.py is same as regressions.py but redirects to regressions.py I will be thankful for any hints how to solve it.
CodePudding user response:
The problem is, as stated in the error message, a circular import issue.
regressions.py
from .mainScreen import MainScreen
mainScreen.py
from .regressions import Regressions
regressions
imports mainScreen
and mainScreen
imports regressions
You have to find a way to remove this dependency.
Maybe this could help: Python circular import in custom package and init.py
CodePudding user response:
I would organize it in differen way.
In main.py
I would first create MainScreen
and Regressions
and later assign classes to .another
And then you don't have to import MainScreen
in regressions.py
and Regressions
in MainScreen.py
because all it done in main.py
# create screens
main_frame = MainScreen(root)
regressions_frame = Regressions(root)
# assing screens to other screens
main_frame.another = regressions_frame
regressions_frame.another = main_fram
But this may need different method to show it.
I would use Frame
to create screens and later I could use .pack()
to show screen in window , and .pack_forget()
to remove previous screen from window.
It is also good idea because it doesn't destroy
screen so it has all old values - so if you display again the same screen then you still have old values (in Entry
, Checkbox
, etc.) and Regressions
may still access values which are in MainScreen
, and MainScreen
can access values which are in Regressions
mainScreen.py
import tkinter as tk
class MainScreen(tk.Frame):
def __init__(self, master):
super().__init__(master)
# keep `root` in `self.master`
#self.master = master # super().__init__(master) should do it automatically
self.label = tk.Button(self, text="Regressions", command=self.load_new)
self.label.pack()
self.another = None
def load_new(self):
if self.another:
# hide current screen (without destroying)
self.pack_forget()
# show another screen
self.another.pack()
regressions.py
import tkinter as tk
class Regressions(tk.Frame):
def __init__(self, master):
super().__init__(master)
# keep `root` in `self.master`
#self.master = master # super().__init__(master) should do it automatically
self.label = tk.Button(self, text="Home", command=self.load_new)
self.label.pack()
self.another = None
def load_new(self):
if self.another:
# hide current screen (without destroying)
self.pack_forget()
# show another screen
self.another.pack()
main.py
import tkinter as tk
from .mainScreen import MainScreen
from .regressions import Regressions
if __name__ == '__main__':
root = tk.Tk()
# create screens
main_frame = MainScreen(root)
regressions_frame = Regressions(root)
# assing screens to other screens
main_frame.another = regressions_frame
regressions_frame.another = main_frame
# show main_frame
main_frame.pack()
root.mainloop()
CodePudding user response:
you should use if __name__=='__main__':
before import the module to avoid circular import
regressions.py
import tkinter as tk
if __name__=='__main__':
from .mainScreen import MainScreen
class Regressions:
def __init__(self, master):
# keep `root` in `self.master`
self.master = master
self.label = tk.Button(self.master, text="Home", command=self.load_new)
self.label.pack()
def load_new(self):
self.label.destroy()
# use `root` with another class
self.another = MainScreen(self.master)
mainScreen.py
import tkinter as tk
if __name__=='__main__':
from .regressions import Regressions
class MainScreen:
def __init__(self, master):
# keep `root` in `self.master`
self.master = master
self.label = tk.Button(self.master, text="Regressions", command=self.load_new)
self.label.pack()
def load_new(self):
self.label.destroy()
# use `root` with another class
self.another = Regressions(self.master)
BTW:
Here more complex version created 10 years ago by Bryan Oakley.
Switch between two frames in tkinter
You can see this method reused in many questions on Stackoverflow.