I try to add a custom message box using the class MessageboxYesNo. But when trying to do so I get an attribute error from the parent class.
import tkinter as tk
from sys import platform
class MainApp(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.parent = parent
self.parent.title("My app")
self.set_app_size_and_position()
self.messagebox1 = MessageboxYesNo(self.parent, "QUIT", "Are you sure you want to quit?")
def set_app_size_and_position(self):
# get screen width and height
self.screen_width = int(self.parent.winfo_screenwidth())
self.screen_height = int(self.parent.winfo_screenheight())
self.app_width_mac = int(self.screen_width/2)
self.app_height_mac = int(self.screen_height)
self.app_x_pos_mac = int(self.screen_width/2)
self.app_y_pos_mac = 0
if platform == "darwin":
self.parent.geometry(f"{self.app_width_mac}x{self.app_height_mac} {self.app_x_pos_mac} {self.app_y_pos_mac}")
class MessageboxYesNo(MainApp):
def __init__(self, parent, title, text):
MainApp.__init__(self, parent)
#inherits the MainApp to be able to get the parent's instance variable value from app_x_pos_mac and app_y_pos_mac
self.parent = parent
self.title = title
self.text = text
self.toplevel = tk.Toplevel(self.parent)
self.toplevel.title(self.title)
#set x- and y-coordinates for centering the messagebox
self.x_pos_messagebox = int(self.app_x_pos_mac (self.app_x_pos_mac/2))
self.y_pos_messagebox = 0
#position the messagebox in the center of the app
self.toplevel.geometry(f"500x300 {self.x_pos_messagebox} {self.y_pos_messagebox}")
#add labels and buttons to messagebox
self.l1=tk.Label(self.toplevel, image="::tk::icons::question")
self.l1.grid(row=0, column=0, pady=(7, 0), padx=(10, 30), sticky="e")
self.l2=tk.Label(self.toplevel,text=self.text)
self.l2.grid(row=0, column=1, columnspan=3, pady=(7, 10), sticky="w")
self.b1=tk.Button(self.toplevel,text="Yes",width = 10)
self.b1.grid(row=1, column=1, padx=(2, 35), sticky="e")
self.b2=tk.Button(self.toplevel,text="No", width = 10)
self.b2.grid(row=1, column=2, padx=(2, 35), sticky="e")
def main():
root = tk.Tk()
app = MainApp(root)
Driver(app.parent)
app.pack()
root.mainloop()
if __name__ == "__main__":
main()
I get this traceroute below. It seems like the parent that gets passed to MainApp.init(self, parent) method in the MessageboxYesNo class, gets confused somehow.
Traceback (most recent call last):
File "//AcademyApp.py", line 307, in <module>
main()
File "//AcademyApp.py", line 300, in main
app = MainApp(root)
File "//AcademyApp.py", line 78, in __init__
self.messagebox1 = MessageboxYesNo(self.parent, "QUIT", "Are you sure you want to quit?")
File "//AcademyApp.py", line 263, in __init__
MainApp.__init__(self, parent)
File "//AcademyApp.py", line 68, in __init__
self.parent.title("My app")
AttributeError: 'Frame' object has no attribute 'title'
It seems that the self.parent in the class MessageboxYesNo gets confused with the self.parent in class MainApp. How can we solve this?
If I try the code without any of my other app code. I get this error instead:
File "/.py", line 12, in __init__
self.messagebox1 = MessageboxYesNo(self.parent, "QUIT", "Are you sure you want to quit?")
File "/.py", line 29, in __init__
MainApp.__init__(self, parent)
File "/.py", line 12, in __init__
self.messagebox1 = MessageboxYesNo(self.parent, "QUIT", "Are you sure you want to quit?")
File "/.py", line 29, in __init__
MainApp.__init__(self, parent)
File "/.py", line 7, in __init__
tk.Frame.__init__(self, parent, *args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/tkinter/__init__.py", line 3116, in __init__
cnf = _cnfmerge((cnf, kw))
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/tkinter/__init__.py", line 105, in _cnfmerge
elif isinstance(cnfs, (type(None), str)):
RecursionError: maximum recursion depth exceeded in __instancecheck__
It is like it is looping, but don't know why?
If I change the MessageboxYesNo class to this it works, but then I can't figure out how to get the value from the instance variable app_x_pos_mac?
class MessageboxYesNo(tk.Frame):
def __init__(self, parent, title, text):
tk.Frame.__init__(self, parent)
self.parent = parent
self.title = title
self.text = text
self.toplevel = tk.Toplevel(self.parent)
self.toplevel.title(self.title)
print(self.parent.app_x_pos_mac) #this can't get the variable value from the MainApp class
CodePudding user response:
It appears the reason it is confusing the parents is because you're passing MainApp
's parent to MessageboxYesNo
. Instead, write:
self.messagebox1 = MessageboxYesNo(self, "QUIT", "Are you sure you want to quit?")
But you will also need to remove the MainApp.__init__(self, parent)
line from your MessageboxYesNo class, otherwise it will continue to recursively loop.