向tk.Tk和tk.Toplevel

时间:2019-11-01 19:08:56

标签: python tkinter

我想为tk.Tktk.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.Tktk.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)。同样,使用混合类(从未尝试过)时,这种预期的行为是吗?

2 个答案:

答案 0 :(得分:2)

我将使用mixin类。为TopWindowRootWindow保留自定义类是创建基础ToplevelTk类专业化的正确解决方案,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()

结果:

enter image description here