我想为tk.Tk
和tk.Toplevel
的实例添加2个方法。前者作为应用程序的根窗口存在,后者由用户创建多次。每个tk.Toplevel
代表应用程序的不同功能,目前存在13种变化。配置该应用程序后,每个时间只能创建一个实例。
解决此问题的一种方法可能是将两个类都作为子类:
class RootWindow(tk.Tk):
def method_1(self):
...
def method_2(self):
...
class TopWindow(tk.Toplevel):
def method_1(self):
...
def method_2(self):
...
由于我只想添加2个功能性方法(它们与使用此类之类的方法,例如winfo_height()
相同),因此子类似乎过高且多余,因为相同的代码编写了两次。因此,另一种方法可能是使用setattr()
,但我觉得这违反了类设计的打开/关闭原则:
def method_1(self):
...
def method_2(self):
...
class RootWindow(tk.Tk):
def __init__(self):
setattr(self, 'method_1', method_1)
setattr(self, 'method_2', method_2)
class TopWindow(tk.Toplevel):
def __init__(self):
setattr(self, 'method_1', method_1)
setattr(self, 'method_2', method_2)
现在我只编写了一次方法并修改了类;从本质上讲,这浓缩了第一种方法,并且实际上是相同的。
鉴于tk.Tk
是一个窗口,而tk.Toplevel
是一个窗口,没有办法通过tkinter
定义所有基于“窗口”的窗口小部件都具有的方法进入?如果所有窗口都来自单个tkinter
类,则不会有问题,但是tk.Tk
的根窗口与tk.Toplevel
的根窗口不同(例如,对于事件绑定,不一定视觉行为)。
编辑:
看看@BryanOakleys解决方案,我发现短绒棉真的不喜欢这样。它们指向未解析的对属性的引用,这些属性我知道子类可以访问,但混合类不能访问。请考虑以下内容:
class Mixin:
def method(self):
width = self.winfo_width()
height = self.winfo_height()
print(f'The window is {width} x {height}')
由于self
无法找到定义的winfo_width
,因此IDE短兵之所以谨慎。但是,我知道它会被tk.Tk
和tk.Toplevel
的子类的类实例调用,但是滥用会导致未定义的行为,例如:
class OtherWindow(Window):
pass
o = OtherWindow()
o.method()
# Attribute error
这有问题吗?提出的解决方案可以工作,但是由于“我知道如何使用”,感觉像被迫工作。一个明显的解决方案是键入提示:
class Mixin:
def method(self: Union[tk.Tk, tk.Toplevel]):
width = self.winfo_width()
height = self.winfo_height()
print(f'The window is {width} x {height}')
因此,短绒棉满足了,并且任何人都可以读取该代码(假设他们不需要查找Union
)。同样,使用混合类(从未尝试过)时,这种预期的行为是吗?
答案 0 :(得分:2)
我将使用mixin类。为TopWindow
和RootWindow
保留自定义类是创建基础Toplevel
和Tk
类专业化的正确解决方案,mixin解决了不想重复的问题代码。
例如:
class CustomMixin():
def method_1(self):
...
def method_2(self):
...
class TopWindow(CustomMixin, tk.Toplevel):
pass
class RootWindow(CustomMixin, tk.Tk):
pass
答案 1 :(得分:0)
编写一个包含您的方法的类,然后在其他类中创建一个class属性,以保留额外方法类的实例。
尝试一下,如果您有任何疑问,请告诉我:
import tkinter as tk
class SomeExtraMethods:
def __init__(self, window):
self.window = window
def size(self):
return [self.window.winfo_width(), self.window.winfo_height()]
class RootWindow(tk.Tk):
def __init__(self):
super().__init__()
self.extra = SomeExtraMethods(self)
tk.Button(self, text='Print root window size', command=self.print_size).pack()
tk.Button(self, text='Open top window', command=self.open_top).pack()
def print_size(self):
print(self.extra.size())
def open_top(self):
top = TopWindow()
class TopWindow(tk.Toplevel):
def __init__(self):
super().__init__()
self.extra = SomeExtraMethods(self)
tk.Button(self, text='Print top window size', command=self.print_size).pack()
def print_size(self):
print(self.extra.size())
if __name__ == '__main__':
RootWindow().mainloop()
结果: