Solución:
Si lo estoy haciendo bien, creo que quieres tener una especie de Clase base que tiene alguna configuración que un conjunto de marcos tienen en común, como por ejemplo, desea tener 10 marcos de 300×400 geometría y de un marrón antecedentes en común y luego tener otro conjunto de marcos con una configuración diferente, al que se puede acceder de forma organizada. Entonces diría que tienes una forma interesante, pero prefiero usar una lista o un diccionario de todos modos.
A continuación, se muestran algunos enfoques para lograr este objetivo.
Enfoque 1
En este enfoque, he creado una función que devuelve un diccionario con todos los marcos creados y contenidos en él como en formato (..., 'F20': tkinter.frame, ...
)
import tkinter as tk
def get_base_frames(num, master, cnf=, **kw):
"""
Create list of frames with common configuration options.
Args:
num (int): Number of frames to be created.
master (tk.Misc): Takes tkinter widget or window as a parent for the frames.
cnf (dict): configuration options for all the frames.
kw: configuration options for all the frames.
Return:
Dictionary of frames (..., 'F20': tkinter.frame, ...).
"""
return f'Fn+1': tk.Frame(master, cnf=cnf, **kw) for n in range(num)
if __name__ == "__main__":
root = tk.Tk()
frame_holder = get_base_frames(10, root, width=50, height=50, bg='brown')
# Frames can be accessed through their names like so.
print(frame_holder.get('F1'))
Enfoque 2
Aquí he usado clase y objetos. Donde hice esta clase Frames
aunque puedes nombrarlo como quieras. También agregué algún método importante como cget()
y configure()
, a través de estos métodos, una vez obtenga un valor para una opción y configure las opciones para todos los marcos respectivamente. Hay métodos más útiles como bind()
y bind_all()
si los necesita, simplemente modifique esta clase según su necesidad.
import tkinter as tk
class Frames(object):
def __init__(self, master=None, cnf=, **kw):
super().__init__()
num = cnf.pop('num', kw.pop('num', 0))
for n in range(num):
self.__setattr__(f'Fn+1', tk.Frame(master, cnf=cnf, **kw))
def configure(self, cnf=, **kw):
"""Configure resources of a widget.
The values for resources are specified as keyword
arguments. To get an overview about
the allowed keyword arguments call the method keys.
"""
for frame in self.__dict__:
frame = self.__getattribute__(frame)
if isinstance(frame, tk.Frame):
if not cnf and not kw:
return frame.configure()
frame.configure(cnf=cnf, **kw)
config = configure
def cget(self, key):
"""Return the resource value for a KEY given as string."""
for frame in self.__dict__:
frame = self.__getattribute__(frame)
if isinstance(frame, tk.Frame):
return frame.cget(key)
__getitem__ = cget
if __name__ == "__main__":
root = tk.Tk()
frame_holder = Frames(root, num=10, width=10,
bd=2, relief='sunken', bg='yellow')
# Frames can be accessed through their naems like so.
print(frame_holder.F4)
print(frame_holder['bg'])
frame_holder.config(bg='blue')
print(frame_holder['bg'])
Enfoque 3
Si quieres tener tramas configuradas de forma diferente contenidas en una clase, donde todos esos marcos tienen algún método en común o algún atributo en común.
import tkinter as tk
class BaseFrame(tk.Frame):
def __init__(self, master=None, cnf=, **kw):
super().__init__(master=master, cnf=, **kw)
def common_function(self):
"""This function will be common in every
frame created through this class."""
# Do something...
class FrameHolder(object):
def __init__(self, master=None, cnf=, **kw):
kw = tk._cnfmerge((cnf, kw))
num = kw.pop('num', len(kw))
for n in range(num):
name = f'Fn+1'
cnf = kw.get(name)
self.__setattr__(name, BaseFrame(master, cnf))
if __name__ == "__main__":
root = tk.Tk()
holder = FrameHolder(root,
F1=dict(width=30, height=40, bg='black'),
F2=dict(width=50, height=10, bg='green'),
F3=dict(width=300, height=350, bg='blue'),
F4=dict(width=100, height=100, bg='yellow'),
)
print(holder.F1)
print(holder.__dict__)
Enfoque 4
Este es el enfoque que OP está tratando de lograr.
import tkinter as tk
class BaseClass(tk.Frame):
def __init__(self, master, cnf=, **kw):
kw = tk._cnfmerge((cnf, kw))
cnf = [(i, kw.pop(i, None))
for i in ('pack', 'grid', 'place') if i in kw]
tk.Frame.__init__(self, master, **kw)
self.master = master
if cnf:
self.__getattribute__(cnf[-1][0])(cnf=cnf[-1][1])
class Container(tk.Frame):
"""Container class which can contain tkinter widgets.
Geometry (pack, grid, place) configuration of widgets
can also be passed as an argument.
For Example:-
>>> Container(root, widget=tk.Button,
B5=dict(width=30, height=40, bg='black',
fg='white', pack=(), text='Button1'),
B6=dict(width=50, height=10, bg='green', text='Button2',
place=dict(relx=0.5, rely=1, anchor='s')))
"""
BaseClass = BaseClass
def __init__(self, master=None, cnf=, **kw):
kw = tk._cnfmerge((cnf, kw))
wid = kw.pop('widget', tk.Frame)
for name, cnf in kw.items():
geo = [(i, cnf.pop(i, None))
for i in ('pack', 'grid', 'place') if i in cnf]
setattr(Container, name, wid(master, cnf))
if geo:
manager, cnf2 = geo[-1]
widget = getattr(Container, name)
getattr(widget, manager)(cnf=cnf2)
if __name__ == "__main__":
root = tk.Tk()
Container(root, widget=Container.BaseClass,
F1=dict(width=30, height=40, bg='black', relief='sunken',
pack=dict(ipadx=10, ipady=10, fill='both'), bd=5),
F2=dict(width=50, height=10, bg='green',
pack=dict(ipadx=10, ipady=10, fill='both')),
)
Container(root, widget=tk.Button,
B5=dict(width=30, height=40, bg='black',
fg='white', pack=, text='Button1'),
B6=dict(width=50, height=10, bg='green', text='Button2',
place=dict(relx=0.5, rely=1, anchor='s')),
)
print(Container.__dict__)
root.mainloop()
Se puede hacer mucho y se puede modificar según las necesidades de cada uno, estos son solo algunos enfoques que creo que funcionarán muy bien para automatizar y mantener un conjunto de marcos en forma y juntos.
Puede haber varias formas de hacer esto o tal vez algo mejor y eficiente que estas, no dude en dar sugerencias y compartir algo nuevo.
Una solución a este problema, creo, ya que no entiendo completamente su pregunta, pero esta fue mi solución:
import tkinter as tk
from tkinter import Frame,Button
class BaseClass(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.master = master
self.pack()
class Holder_frame(tk.Frame):
def __init__(self, master, frames=2):
tk.Frame.__init__(self, master)
self.master = master
self.frame_names = []
for i in range(frames):
Holder_frame.create_frames("F"+str(i+1), self)
@classmethod
def create_frames(cls, name, master):
setattr(cls, name, tk.Frame(master))
if __name__ == "__main__":
root = tk.Tk()
def raise1():
print(type(Holder_frame.F1))
def raise2():
print(type(Holder_frame.F2))
holder=Holder_frame(root,frames=2)
holder.grid(row=1,column=0)
b1 = tk.Button(root, text='1', command=raise1)
b1.grid(row=0,column=0)
b2 = tk.Button(root, text='2', command=raise2)
b2.grid(row=0,column=1)
print(Holder_frame.__dict__.items())
root.mainloop()
El uso de setattr
permite agregar variables a la clase, como si escribiera una función en el código. Esto le permite acceder a marcos desde fuera de la clase como una especie de “variable global”.
Usé un archivo para probar si también funciona afuera como un módulo importado:
# main.py
from nested_class import Holder_frame
import tkinter as tk
root = tk.Tk()
holder=Holder_frame(root,frames=1000)
holder.grid(row=1,column=0)
print(Holder_frame.__dict__.items())
root.mainloop()
Espero que esto responda tu pregunta,
Jaime
EDITAR:
Después de pensar que hay, lo que creo, que sea un sistema más limpio para lo que quieres. Con el código de esta publicación, se puede ver que su mi sistema escrito podría ser reemplazado por un ttk.Notebook
, y quitando la barra superior usando style.layout('TNotebook.Tab', [])
, se puede ver que obtendría un widget de marco que podría tener widgets de marco dentro de él:
import tkinter as tk
import tkinter.ttk as ttk
class multiframe_example:
def __init__(self, master):
self.master = master
style = ttk.Style()
style.layout('TNotebook.Tab', [])
notebook = ttk.Notebook(self.master)
notebook.grid(row=0, column=0)
self.master.grid_rowconfigure(0, weight=1)
self.master.grid_columnconfigure(0, weight=1)
tab1 = tk.Frame(self.master, width=500, height=500, background="green")
tab2 = tk.Frame(self.master, width=500, height=500)
tab3 = tk.Frame(self.master, width=500, height=500)
notebook.add(tab1)
notebook.add(tab2)
notebook.add(tab3)
notebook.select(0) # select tab 1
notebook.select(1) # select tab 2
notebook.select(2) # select tab 3
def main():
root = tk.Tk()
root.geometry("500x500")
multiframe_example(root)
root.mainloop()
if __name__ == '__main__':
main()
¡Espero que este código pueda ayudarte y haga lo que quieras!
Sección de Reseñas y Valoraciones
Si te animas, tienes la opción de dejar un tutorial acerca de qué le añadirías a este enunciado.