I have been struggling for a week with an oop in Python while writing a tkinter application. I have simplified the app to show the problem only. I have two frames and each of them has two buttons - the button in the first row increases the frames´ number (self.top_frame_number
or self.bottom_frame_number
and the button in the second row should get me a number from the other frame (so the button in the top frame should get me the number from the bottom frame).
I can´t figure out how to accomplish this, this means I don´t know how to access a class´ instance attribute from another class´ instance, while both of them are attributes of the main Application class.
I´ve been searching through questions but haven´t found similar example and the answers to another questions didn´t help me in my struggle. Here is the whole code:
import tkinter as tk
class TopFrame:
def __init__(self, parent):
self.parent = parent
self.topframe = tk.LabelFrame(self.parent, text="Top frame", width=300, height=100, bd=2)
self.topframe.pack(side="top", fill="both")
self.top_frame_number = 100
# FIRST ROW WIDGETS
self.topframe_tfn_label = tk.Label(self.topframe, text="number: ")
self.topframe_tfn_label.grid(row=0, column=0, sticky="w")
self.topframe_tfn = tk.Label(self.topframe)
self.topframe_tfn.grid(row=0, column=1)
self.topframe_tfn.configure(text=self.top_frame_number)
self.topframe_tfn_button = tk.Button(self.topframe,
text="increase",
command=lambda: self.topframe_increase_top_frame_number())
self.topframe_tfn_button.grid(row=0, column=2, pady=2, sticky="w")
# SECOND ROW WIDGETS
self.topframe_bfn_label = tk.Label(self.topframe, text="bottom frame number: ")
self.topframe_bfn_label.grid(row=1, column=0, sticky="w")
self.topframe_bfn = tk.Label(self.topframe)
self.topframe_bfn.grid(row=1, column=1)
self.topframe_bfn.configure(text="?")
self.topframe_bfn_button = tk.Button(self.topframe,
text="get bottom frame number",
command=lambda: self.topframe_get_bottom_frame_number())
self.topframe_bfn_button.grid(row=1, column=2, pady=2, sticky="e")
def topframe_increase_top_frame_number(self):
self.top_frame_number += 1
self.topframe_tfn.configure(text=self.top_frame_number)
def topframe_get_bottom_frame_number(self):
pass
# I AM STUCK HERE - How to get to the top frame number?
class BottomFrame:
def __init__(self, parent):
self.parent = parent
self.bottomframe = tk.LabelFrame(self.parent, text="Bottom frame", width=300, height=100, bd=2)
self.bottomframe.pack(side="top", fill="both")
self.bottom_frame_number = 200
# FIRST ROW
self.bottomframe_tfn_label = tk.Label(self.bottomframe, text="number: ")
self.bottomframe_tfn_label.grid(row=0, column=0, sticky="w")
self.bottomframe_tfn = tk.Label(self.bottomframe)
self.bottomframe_tfn.grid(row=0, column=1)
self.bottomframe_tfn.configure(text=self.bottom_frame_number)
self.bottomframe_tfn_button = tk.Button(self.bottomframe,
text="increase",
command=lambda: self.bottomframe_increase_bottom_frame_number())
self.bottomframe_tfn_button.grid(row=0, column=2, pady=2, sticky="e")
# SECOND ROW
self.bottomframe_bfn_label = tk.Label(self.bottomframe, text="top frame number: ")
self.bottomframe_bfn_label.grid(row=1, column=0, sticky="w")
self.bottomframe_bfn = tk.Label(self.bottomframe)
self.bottomframe_bfn.grid(row=1, column=1)
self.bottomframe_bfn.configure(text="?")
self.bottomframe_bfn_button = tk.Button(self.bottomframe,
text="get top frame number",
command=lambda: self.bottomframe_get_top_frame_number())
self.bottomframe_bfn_button.grid(row=1, column=2, pady=2, sticky="e")
def bottomframe_increase_bottom_frame_number(self):
self.bottom_frame_number += 1
self.bottomframe_tfn.configure(text=self.bottom_frame_number)
def bottomframe_get_top_frame_number(self):
pass
# I AM STUCK HERE - How to get to the top frame number?
class Application:
def __init__(self, master):
self.master = master
self.master.title("Show me numbers!")
# -- FRAMES --
self.top_frame = TopFrame(self.master)
self.bottom_frame = BottomFrame(self.master)
if __name__ == "__main__":
root = tk.Tk()
Application(root)
root.mainloop()
I have been trying to learn the oop from different materials over the web but with no success. So I tried:
TopFrame
and BottomFrame
classes are equal, not parent-child__init__
as it lead to an infinite recursion error.How should I access the number in other class´ instance correctly?
jasonharper has pointed me to the right direction. I added the reference to the master Application class and it works. So the whole code is:
import tkinter as tk
class TopFrame:
def __init__(self, parent, master):
self.parent = parent
self.master = master
self.topframe = tk.LabelFrame(self.parent, text="Top frame", width=300, height=100, bd=2)
self.topframe.pack(side="top", fill="both")
self.top_frame_number = 100
# FIRST ROW
self.topframe_tfn_label = tk.Label(self.topframe, text="number: ")
self.topframe_tfn_label.grid(row=0, column=0, sticky="w")
self.topframe_tfn = tk.Label(self.topframe)
self.topframe_tfn.grid(row=0, column=1)
self.topframe_tfn.configure(text=self.top_frame_number)
self.topframe_tfn_button = tk.Button(self.topframe,
text="increase",
command=lambda: self.topframe_increase_top_frame_number())
self.topframe_tfn_button.grid(row=0, column=2, pady=2, sticky="w")
# SECOND ROW
self.topframe_bfn_label = tk.Label(self.topframe, text="bottom frame number: ")
self.topframe_bfn_label.grid(row=1, column=0, sticky="w")
self.topframe_bfn = tk.Label(self.topframe)
self.topframe_bfn.grid(row=1, column=1)
self.topframe_bfn.configure(text="?")
self.topframe_bfn_button = tk.Button(self.topframe,
text="get bottom frame number",
command=lambda: self.topframe_get_bottom_frame_number())
self.topframe_bfn_button.grid(row=1, column=2, pady=2, sticky="e")
def topframe_increase_top_frame_number(self):
self.top_frame_number += 1
self.topframe_tfn.configure(text=self.top_frame_number)
def topframe_get_bottom_frame_number(self):
self.topframe_bfn.configure(text=self.master.bottom_frame.bottom_frame_number)
class BottomFrame:
def __init__(self, parent, master):
self.parent = parent
self.master = master
self.bottomframe = tk.LabelFrame(self.parent, text="Bottom frame", width=300, height=100, bd=2)
self.bottomframe.pack(side="top", fill="both")
self.bottom_frame_number = 200
# FIRST ROW
self.bottomframe_bfn_label = tk.Label(self.bottomframe, text="number: ")
self.bottomframe_bfn_label.grid(row=0, column=0, sticky="w")
self.bottomframe_bfn = tk.Label(self.bottomframe)
self.bottomframe_bfn.grid(row=0, column=1)
self.bottomframe_bfn.configure(text=self.bottom_frame_number)
self.bottomframe_bfn_button = tk.Button(self.bottomframe,
text="increase",
command=lambda: self.bottomframe_increase_bottom_frame_number())
self.bottomframe_bfn_button.grid(row=0, column=2, pady=2, sticky="e")
# SECOND ROW
self.bottomframe_tfn_label = tk.Label(self.bottomframe, text="top frame number: ")
self.bottomframe_tfn_label.grid(row=1, column=0, sticky="w")
self.bottomframe_tfn = tk.Label(self.bottomframe)
self.bottomframe_tfn.grid(row=1, column=1)
self.bottomframe_tfn.configure(text="?")
self.bottomframe_tfn_button = tk.Button(self.bottomframe,
text="get top frame number",
command=lambda: self.bottomframe_get_top_frame_number())
self.bottomframe_tfn_button.grid(row=1, column=2, pady=2, sticky="e")
def bottomframe_increase_bottom_frame_number(self):
self.bottom_frame_number += 1
self.bottomframe_bfn.configure(text=self.bottom_frame_number)
def bottomframe_get_top_frame_number(self):
self.bottomframe_tfn.configure(text=self.master.top_frame.top_frame_number)
class Application:
def __init__(self, master):
self.master = master
self.master.title("Show me numbers!")
# -- FRAMES --
self.top_frame = TopFrame(self.master, self)
self.bottom_frame = BottomFrame(self.master, self)
if __name__ == "__main__":
root = tk.Tk()
Application(root)
root.mainloop()
If there is a better way how to reference the Application class from TopFrame or BottomFrame classes without specifying self
within Application´s __init__
(this means without self.top_frame = TopFrame(self.master, self)
and self.bottom_frame = BottomFrame(self.master, self)
) and corresponding reference in TopFrame and BottomFrame classes (self.master = master
), I´m open minded...