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

时间:2015-10-01 09:07:52

标签: python class tkinter

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

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

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

class App(Frame):
  [...]

我想明白为什么会这样。为什么我们不能将Frame的容器,窗口子类化?看来这是第一个例子中的语句所做的,为什么不在类定义中呢?

编辑(遵循布莱恩奥克利的回答):

我想在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子类一样,但是在最高级别?

1 个答案:

答案 0 :(得分:4)

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

我个人从框架继承,因为我发现它很方便。我的一些GUI需要能够打开多个相同的窗口。通过将我的主代码放在一个框架中,我可以通过创建框架的多个实例并将它们打包在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__方法。

你问过工作的例子,这里有几个:

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

中的回复