I am learning OO programming by converting an existing app programmed in straight tkinter. I need to be able to access an entrybox in top_frame from a button in left_frame. I have managed to achieve this by passing an instance of top_frame to Left_frame and with the program as listed here it works. However I wanted to put all of the methods into a Commands class for clarity so that the frame classes set the UI and the Commands class does the work. In the code I can call methods in the commands class from left_frame and in simple terms they work. My problem is that I need to use the contents of top_frame.g_round in the list golfers method in the Commands class. The code as shown works if the command for my_list_btn is "self.list_golfers" (using the left_frame method) but if I try to use the Commands class version by calling "Commands.list_golfers" I get errors when trying to pass the required attributes. I have tried various answers but each give me errors. Could anyone help by showing me how to pass the necessary attributes to the method in the Commands class. I have gone through many videos/texts to try to work it out but clearly I have missed something. Thanks
from tkinter import *
import tkinter as tk
from ttkbootstrap.constants import *
import ttkbootstrap as tb
from ttkbootstrap import Style
from ttkbootstrap.scrolled import ScrolledText, ScrolledFrame
#import sqlite3
#from sqlite3 import Error
from ttkbootstrap.dialogs import Messagebox
class Commands(tb.Frame):
def __init__(self,parent, left_frame_instance):
super().__init__(parent)
l_frame = left_frame_instance
def list_golfers(self):
x= self.l_frame.tframe1.g_round.get()
print('list_golfers')
print(x)
def new_golfer():
print('new_golfer')
def report():
print('report')
def select():
print('select')
class Top_Frame(tb.Frame):
def __init__(self, parent): # Create widgets
super().__init__(parent,width=900, height=200, bootstyle ='light')
self.pack(padx=10, pady=5, fill=BOTH)
self.g_round = tb.Entry(self,width=3, font=("Courier",10))
self.g_round.grid(row = 0, column=1,padx=10,pady=10)
self.round_label = tb.Label(self, text = "You must enter the round number before proceeding --> ", font=('Courier', 10))
self.round_label.grid(row=0,column=0,padx=10,pady=10)
class Left_Frame(tb.Frame):
def __init__(self,parent, top_frame_instance):
super().__init__(parent,width=400, height=600, bootstyle ='light')
self.tframe1 = top_frame_instance # Store reference to Frame1 instance
self.pack(side='left',padx=10, pady=5, fill=BOTH, expand= True)
self.create_Lwidgets()
def list_golfers(self):
x= self.tframe1.g_round.get()
print('list_golfers')
print(x)
def create_Lwidgets(self):
my_list_btn=tb.Button(self,text='list',bootstyle='success', command= self.list_golfers)
my_list_btn.grid(row=0, column=0,padx=5,pady=5)
list_frame = tb.Frame(self,width=200, height=800,bootstyle='primary')
list_frame.grid(row=1, column=0,padx=5,pady=5, rowspan=18)
my_listbox=Listbox(list_frame)
my_listbox.pack(padx=0,pady=15, side = LEFT,fill='both')
my_scrollbar = Scrollbar(list_frame)
my_scrollbar.pack(side = RIGHT, fill = BOTH)
my_listbox.config(yscrollcommand = my_scrollbar.set)
my_scrollbar.config(command = my_listbox.yview)
golfer_button= tb.Button(self, text='New Golfer',bootstyle ='success',command = Commands.new_golfer)
golfer_button.grid(row=21, column=0,padx=10,pady=10)
report_button= tb.Button(self, text='Generate Report',bootstyle ='success',command = Commands.report)
report_button.grid(row=22, column=0,padx=10,pady=10)
select_btn = tb.Button(self, text="Select", bootstyle = SUCCESS,command = Commands.select)
select_btn.grid(row=4, column=1, pady=5, padx=5)
id_label=tb.Label(self,text = 'id')
id_label.grid(row=2,column=2,padx=10)
g_id = tb.Entry(self,width=3, font=("Courier",10), state='disabled')
g_id.grid(row = 2, column=3,padx=5,pady=5)
class Right_Frame(tb.Frame):
def __init__(self,parent):
super().__init__(parent,width=400, height=600, bootstyle ='light')
self.pack(side= 'right',padx=10, pady=5, fill=BOTH, expand=True)
self.create_Rwidgets()
#create widgets
def create_Rwidgets(self):
my_label = tb.Label(self, text = "Batch Scores", font=('Courier', 10))
my_label.grid(row=0,column=0,padx=10,pady=10)
Ts = Listbox(self, height = 30, width = 30)
Ts.grid(row= 2, column= 0, sticky= N, columnspan = 5, padx= 10, pady= 15)
class MyApp(tb.Window):
def __init__(self):
super().__init__(themename = 'terry')
# self.root = root
self.title("TTKBootstrap OOP Example")
self.geometry("1000x1000")
top_frame = Top_Frame(self)
left_frame = Left_Frame(self,top_frame)
right_frame = Right_Frame(self)
commands = Commands(self, left_frame)
if __name__ == "__main__":
app = MyApp() # Create an instance of MyApp
app.mainloop()
Problem is that you mix "methods of instance" with "static methods"
Some of your example functions don't need self
so they can be used as Command.function
(static methods) but list_golfers
needs self
to access self.l_frame
and it needs to create command = Command()
and later use command.list_golfers
But I found other problem with this - class Left_Frame()
needs access to variable command
which is created later, but class Command()
needs access to variable left_frame
- and this makes conflict - you can't put Command()
before Left_Frame
because conflict still exists.
I would remove left_frame
from Command()
and use self.parent.left_frame
(or rather self.master.left_frame
) to access left_frame
.
Of course it needs to use self.
when you create frame - self.left_frame = Left_Frame(..)
My full working code. I keep instance of Commands()
as self.commands
and Frames use self.master.command
to access functions in this instance.
command=self.master.commands.left_golfers
Frankly I would move all functions to MyApp and then it would need self.master
command=self.master.left_golfers
And in all functions in Command()
I use self
because sooner or later they may need access to self.parent
#from tkinter import * # PEP8: `import *` is not preferred
import tkinter as tk
#from ttkbootstrap.constants import * # PEP8: `import *` is not preferred
import ttkbootstrap as tb
from ttkbootstrap import Style
from ttkbootstrap.scrolled import ScrolledText, ScrolledFrame
#import sqlite3
#from sqlite3 import Error
from ttkbootstrap.dialogs import Messagebox
class Commands():
def __init__(self, parent):
super().__init__()
self.parent = parent
def list_golfers(self):
x = self.parent.left_frame.top_frame.g_round.get()
print('list_golfers')
print(x)
def new_golfer(self):
print('new_golfer')
def report(self):
print('report')
def select(self):
print('select')
class Top_Frame(tb.Frame):
def __init__(self, parent): # Create widgets
super().__init__(parent, width=900, height=200, bootstyle='light')
self.pack(padx=10, pady=5, fill="both")
self.g_round = tb.Entry(self, width=3, font=("Courier",10))
self.g_round.grid(row = 0, column=1, padx=10, pady=10)
self.round_label = tb.Label(self, text="You must enter the round number before proceeding --> ", font=('Courier', 10))
self.round_label.grid(row=0, column=0, padx=10, pady=10)
class Left_Frame(tb.Frame):
def __init__(self, parent, top_frame):
super().__init__(parent, width=400, height=600, bootstyle='light')
self.top_frame = top_frame # Store reference to Frame1 instance
self.pack(side='left',padx=10, pady=5, fill="both", expand=True)
self.create_left_widgets()
def list_golfers(self):
x = self.top_frame.g_round.get()
print('list_golfers')
print(x)
def create_left_widgets(self):
my_list_btn = tb.Button(self, text='list', bootstyle='success', command=self.master.commands.list_golfers)
my_list_btn.grid(row=0, column=0, padx=5, pady=5)
list_frame = tb.Frame(self,width=200, height=800, bootstyle='primary')
list_frame.grid(row=1, column=0, padx=5, pady=5, rowspan=18)
my_listbox = tk.Listbox(list_frame)
my_listbox.pack(padx=0, pady=15, side="left", fill='both')
my_scrollbar = tk.Scrollbar(list_frame)
my_scrollbar.pack(side="right", fill="both")
my_listbox.config(yscrollcommand=my_scrollbar.set)
my_scrollbar.config(command=my_listbox.yview)
golfer_button = tb.Button(self, text='New Golfer', bootstyle='success', command=self.master.commands.new_golfer)
golfer_button.grid(row=21, column=0, padx=10, pady=10)
report_button = tb.Button(self, text='Generate Report', bootstyle='success', command=self.master.commands.report)
report_button.grid(row=22, column=0, padx=10, pady=10)
select_btn = tb.Button(self, text="Select", bootstyle="success", command=self.master.commands.select)
select_btn.grid(row=4, column=1, pady=5, padx=5)
id_label = tb.Label(self, text='id')
id_label.grid(row=2, column=2, padx=10)
g_id = tb.Entry(self, width=3, font=("Courier", 10), state='disabled')
g_id.grid(row=2, column=3, padx=5, pady=5)
class Right_Frame(tb.Frame):
def __init__(self,parent):
super().__init__(parent, width=400, height=600, bootstyle='light')
self.pack(side='right', padx=10, pady=5, fill="both", expand=True)
self.create_right_widgets()
#create widgets
def create_right_widgets(self):
my_label = tb.Label(self, text="Batch Scores", font=('Courier', 10))
my_label.grid(row=0, column=0, padx=10, pady=10)
ts = tk.Listbox(self, height=30, width=30)
ts.grid(row=2, column=0, sticky="n", columnspan=5, padx=10, pady=15)
class MyApp(tb.Window):
def __init__(self):
super().__init__() #themename = 'terry')
# self.root = root
self.title("TTKBootstrap OOP Example")
self.geometry("1000x1000")
self.commands = Commands(self)
self.top_frame = Top_Frame(self)
self.left_frame = Left_Frame(self, self.top_frame)
self.right_frame = Right_Frame(self)
if __name__ == "__main__":
app = MyApp() # Create an instance of MyApp
app.mainloop()