Если я правильно понимаю, я думаю, вы имеете в виду иметь какой-то базовый класс , который имеет некоторую конфигурацию, которая является общей для набора кадров, например, вы хотите иметь 10 кадров 300x400 геометрия и общий фон коричневый , а затем еще один набор кадров с другой конфигурацией , доступ к которым может быть организован. Тогда я бы сказал, что у вас есть интересный способ, но я бы предпочел использовать список или словарь.
Вот несколько подходов для достижения этой цели.
Подход 1
В этом подходе я создал функцию, которая возвращает словарь со всеми фреймами, созданными и содержащимися в нем, как в формате ({..., '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'F{n+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'))
Подход 2
Здесь я использовал класс и объекты. Где я сделал этот класс Frames
, хотя вы можете называть его как хотите. Я также добавил некоторые важные методы, такие как cget()
и configure()
, с помощью этих методов, когда можно получить значение параметра и настроить параметры для всех кадров соответственно. Есть более полезные методы, такие как bind()
и bind_all()
, если они вам нужны, просто измените этот класс в соответствии с вашими потребностями.
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'F{n+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'])
Подход 3
Если вы хотите иметь по-разному настроенных фреймов, содержащихся в одном классе, , где все эти фреймы имеют какой-то общий метод или какой-то общий атрибут.
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'F{n+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__)
Подход 4
Это подход, которого пытается достичь OP.
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()
Многое может быть сделано и может быть изменено в соответствии с вашими потребностями, эти это всего лишь некоторые подходы, которые, как мне кажется, будут очень хорошо работать для автоматизации и сохранения набора фреймов в форме и вместе.
Может быть несколько способов сделать это или, может быть, что-то лучше и эффективнее, чем эти, не стесняйтесь давать предложения и делиться чем-то новым.