Python:为啥 Tkinter 类实例化必须使用 Frame?

Posted

技术标签:

【中文标题】Python:为啥 Tkinter 类实例化必须使用 Frame?【英文标题】:Python: why must Tkinter class instantiation use a Frame?Python:为什么 Tkinter 类实例化必须使用 Frame? 【发布时间】:2015-12-29 06:33:18 【问题描述】:

如果我想简单地用语句创建一个 Tkinter GUI,我可以这样做:

from Tkinter import *
root = Tk()
root.title("Test Window")
tkFrame = Frame(root)
tkButton = Button(tkFrame)
[...]

然而,文档建议将 Tkinter 与类定义一起使用,子类化 Frame 小部件:

class App(Frame):
  [...]

我想了解为什么会这样。为什么我们不能子类化 Frame 的容器,即窗口?看起来这就是第一个示例中的语句所做的,那么为什么不在类定义中呢?

编辑(按照 Bryan Oakley 的回答):

我想在 Tkinter 的***别进行实例化,我认为它是 Tk()(虽然我遇到过引用说 Frame 是***别,但没关系)。实际上,以下将创建一个窗口:

from Tkinter import *
class Application(Tk):
  pass
app = Application()
app.mainloop()

...但是当我尝试添加小部件时,我会收到错误或两个窗口,小部件位于新窗口中,具体取决于我如何构建代码。这是一个基本示例,它将生成带有按钮的第二个窗口:

from Tkinter import *
class Application(Tk):
  tkBtn = Button()
  tkBtn.pack()
app = Application()
app.mainloop()

使用self__init__ 等会产生错误。有人可以指出我在***别实例化 Tkinter 的工作代码吗?就像我看到的所有 Frame 子类一样,但在***别?

【问题讨论】:

您遇到的任何引用说明 Frame 是“Tkinter 的***别”都是错误的。 【参考方案1】:

没有什么说 tkinter 类必须从框架继承。您可以从任何 tkinter 小部件或任何其他类继承。如果您找到了另有说明的文档,则该文档是错误的。使用Frame 是一个合乎逻辑的选择,因为它被设计为其他小部件的容器,但它不是唯一的选择。

我个人从框架继承,因为我觉得它很方便。我的一些 GUI 需要能够打开多个相同的窗口。 通过将我的主要代码放在 Frame 中,我可以创建多个窗口,只需创建框架的多个实例,并将它们打包到 Toplevel 小部件中。

当您从Tk 继承时,您只能拥有一个实例。在现实世界中,这通常就足够了,这样做绝对没有错。因为我个人编写了相当多的 tkinter 程序,所以让它们都以完全相同的方式开始对我来说很方便。

另一个不错的选择是Canvas,因为您可以轻松添加背景图片,而Frame 则无法做到这一点。

底线:您绝对不需要从 Frame 继承。继承你想要的任何东西。


(以下是针对原始问题的编辑而编写的)

参考此代码:

from Tkinter import *
class Application(Tk):
  tkBtn = Button()
  tkBtn.pack()
app = Application()
app.mainloop()

您看到两个窗口的原因是您没有正确创建类。在创建小部件之前,您需要调用超类的__init__ 方法,因为这实际上是创建根窗口的方法。因为你不这样做,所以你最终会得到两个窗口。当您将一个按钮添加到尚未构建的根窗口时,您会得到一个隐式创建的,当您的子类完成初始化时,您会得到另一个。

解决办法是不走捷径,而是正确初始化类:

from Tkinter import *
class Application(Tk):
    def __init__(self):
        Tk.__init__(self)
        tkBtn = Button()
        tkBtn.pack()
app = Application()
app.mainloop()

请注意,这不是特定于 tkinter 的问题。子类化时,除非有明确的理由,否则应始终调用超类的__init__ 方法。

您要求提供工作示例,这里有几个:

https://***.com/a/22424245/7432 https://***.com/a/11405393/7432

您可能还想阅读问题Inheriting from Frame or not in a Tkinter application中的回复

【讨论】:

@DhaLee:我已经更新了我的答案以解决您的其他问题。

以上是关于Python:为啥 Tkinter 类实例化必须使用 Frame?的主要内容,如果未能解决你的问题,请参考以下文章

为啥通过 python 默认变量初始化变量会在对象实例化过程中保持状态?

__init__ 为啥python类需要初始化

Python设计模式:创建型

Python - 从派生类实例化的对象的序列号

█■为啥要用实现接口的类实例化接口呢?

C#为啥接口可以实例化一个实现该接口的类?