Estou aprendendo programação orientada a objetos (OO) convertendo um aplicativo existente programado em Tkinter. Preciso acessar uma caixa de entrada em top_frame a partir de um botão em left_frame. Consegui isso passando uma instância de top_frame para Left_frame e, com o programa listado aqui, funciona. No entanto, eu queria colocar todos os métodos em uma classe Commands para maior clareza, de modo que as classes de frame configurassem a interface do usuário (UI) e a classe Commands fizesse o trabalho. No código, posso chamar métodos na classe commands de left_frame e, em termos simples, eles funcionam. Meu problema é que preciso usar o conteúdo de top_frame.g_round no método list golfers na classe Commands. O código mostrado funciona se o comando para my_list_btn for "self.list_golfers" (usando o método left_frame), mas se eu tentar usar a versão da classe Commands chamando "Commands.list_golfers", recebo erros ao tentar passar os atributos necessários. Tentei várias respostas, mas todas me deram erros. Alguém poderia me ajudar mostrando como passar os atributos necessários para o método na classe Commands? Já assisti a vários vídeos/textos para tentar entender, mas claramente deixei algo passar. Obrigado.
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()
O problema é que você mistura "métodos de instância" com "métodos estáticos"
Algumas de suas funções de exemplo não precisam
self
ser usadas comoCommand.function
( métodos estáticos ), maslist_golfers
precisamself
ser acessadasself.l_frame
e criadascommand = Command()
para uso posterior.command.list_golfers
Mas encontrei outro problema com isso: a classe
Left_Frame()
precisa acessar a variávelcommand
que é criada depois, mas a classeCommand()
precisa acessar a variávelleft_frame
, e isso gera conflito: você não pode colocarCommand()
antesLeft_Frame
porque o conflito ainda existe.Eu removeria
left_frame
deCommand()
e usariaself.parent.left_frame
(ou melhor,self.master.left_frame
) para acessarleft_frame
.Claro que é necessário usar
self.
quando você cria o quadro -self.left_frame = Left_Frame(..)
Meu código funcional completo. Mantenho uma instância de
Commands()
comoself.commands
e uso Framesself.master.command
para acessar funções nesta instância.Francamente eu moveria todas as funções para MyApp e então seria necessário
self.master
E em todas as funções
Command()
eu usoself
porque mais cedo ou mais tarde eles podem precisar de acesso aself.parent
PEP 8 -- Guia de estilo para código Python