在Tkinter应用程序中是否继承Frame

时间:2011-09-04 15:04:11

标签: python tkinter

我已经看到了设置tkinter程序的两种基本方法。是否有理由更喜欢一个到另一个?

from Tkinter import *

class Application():
    def __init__(self, root, title):
        self.root = root
        self.root.title(title) 

        self.label = Label(self.root, text='Hello')
        self.label.grid(row=0, column=0)  

root = Tk()
app = Application(root, 'Sample App')
root.mainloop()

from Tkinter import *

class Application(Frame):
    def __init__(self, title, master=None):
        Frame.__init__(self, master)
        self.grid()
        self.master.title(title) 

        self.label = Label(self, text='Hello')
        self.label.grid(row=0, column=0) 

app = Application('Sample App')
app.mainloop()   

3 个答案:

答案 0 :(得分:26)

我更喜欢*的选项是继承Tk类。我认为这是更合理的选择,因为窗口实际上是您的应用程序。继承Frame对我来说没有任何意义,那么继承自ButtonCanvasLabel。由于您只能拥有一个根,因此您继承的是有意义的。

我还认为,如果您导入import Tkinter as tk而非from Tkinter import *,则会使代码更具可读性。然后,您的所有调用都明确提到了tk模块。我不建议所有模块使用它,但对我而言,这对Tkinter来说是有意义的。

例如:

import Tkinter as tk

class SampleApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.label = tk.Label(text="Hello, world")
        self.label.pack(padx=10, pady=10)

app = SampleApp()
app.mainloop()

*注意:,因为最初写这个答案我改变了我的立场。我现在更愿意继承Frame而不是Tk。这种方式没有真正的优势,它更像是一种哲学选择而不是其他任何东西。无论如何,我相信无论你是继承自Frame还是Tk,我认为这两种选择都比代码中的第一个继承任何东西的例子更好。

如果您希望应用程序支持多个相同的窗口,那么从Frame继承的优势超过Tk。在这种情况下,继承自Frame允许您创建第一个窗口作为root的子项,并将其他窗口创建为Toplevel实例的子项。但是,我发现很少有程序需要这样做。

有关我认为应该如何构建Tkinter程序的更多信息,请参阅问题my answerPython Tkinter program structure

答案 1 :(得分:12)

帧通常用作geometry master for other widgets。 由于应用程序通常具有多个小部件,因此您通常希望将它们全部包含在一个框架中,或者至少使用框架来添加一些borderwidth,填充或其他精确的小部件。

您可能在网络上找到的许多示例代码段都不使用Frame,因为 他们只是想用最短的代码来演示一些功能。

因此,如果需要,请使用Frame,否则请不要。

修改:我认为在Tkinter tutorial中提供了组织GUI的最佳方式:

simpleApp.py:

import Tkinter as tk

class SimpleApp(object):
    def __init__(self, master, **kwargs):
        title=kwargs.pop('title')
        frame=tk.Frame(master, **kwargs)
        frame.pack()
        self.label = tk.Label(frame, text=title)
        self.label.pack(padx=10,pady=10)

if __name__=='__main__':
    root = tk.Tk()
    app = SimpleApp(root,title='Hello, world')
    root.mainloop()

这主要类似于第一个示例,SimpleApp继承自object,而不是Frame。我认为这比继承Frame更好,因为我们没有覆盖任何Frame方法。我更愿意将SimpleApp视为拥有Frame而不是Frame

SimpleApp子类object确实比子类tk.Tk有明显的优势,但是:它可以很容易地将SimpleApp嵌入到更大的应用中:

import simpleApp
import Tkinter as tk

class BigApp(object):
    def __init__(self, master, **kwargs):
        title=kwargs.pop('title')
        frame=tk.Frame(master, **kwargs)
        frame.pack()
        self.simple = simpleApp.SimpleApp(frame,title=title)
        frame.pack(padx=10, pady=10)
        self.simple2 = simpleApp.SimpleApp(frame,title=title)    
        frame.pack()

if __name__=='__main__':
    root = tk.Tk()
    app = BigApp(root,title='Hello, world')
    root.mainloop()

因此,simpleApp.py可以是独立脚本以及可导入模块。 如果您使用继承自SimpleApp的{​​{1}}进行尝试,则最终会产生额外的不受欢迎的窗口。

答案 2 :(得分:1)

将顶级对象设置为从Tk而不是Frame继承可能会有一个优势。当您拥有GUI的动态元素时,就会产生这样的优势,例如: Label要使用textvariable=foo而不是text= 'Label text'设置其内容的Tkinter.DoubleVar

在这种情况下,使用Tkinter.IntVarTkinter.StringVarTkinter.Tk()对象来保存数据非常有用,因为只要设置了这些对象,GUI就会自动更新。但是,要使用这些对象,必须将其master指定为运行的根Tkinter.Tk,实例。如果您明确地使主对象成为Tk的子类然后生成框架和窗口小部件,这会更容易,因此您可以传递import Tkinter as tk class Tkclass(tk.Tk): def __init__(self): tk.Tk.__init__(self) app=Application(self) app.master.title("Animal to Meat") app.mainloop() class Application(tk.Frame): def __init__(self, parent): tk.Frame.__init__(self, parent) self.grid(sticky=tk.N+tk.S+tk.E+tk.W) self.meatvar = tk.StringVar(master=parent) self.meatvar.set("Meat?") self.createWidgets() def createWidgets(self): top=self.winfo_toplevel() top.rowconfigure(0, weight=1) top.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) self.columnconfigure(0, weight=1) self.columnconfigure(1, weight=1) self.columnconfigure(2, weight=1) self.columnconfigure(3, weight=1) self.cowButton = tk.Button(self, text='Cow', command=self.setBeef) self.cowButton.grid(row=0,column=0) self.pigButton = tk.Button(self, text='Pig',command=self.setPork) self.pigButton.grid(row=0,column=1) self.meatLabel = tk.Label(self) self.meatLabel.configure(textvariable=self.meatvar) self.meatLabel.grid(row=0,column=2) self.quit = tk.Button(self, text='Quit',command=self.QuitApp) self.quit.grid(row=0, column=3) def setBeef(self): self.meatvar.set("Beef") def setPork(self): self.meatvar.set("Pork") def QuitApp(self): top=self.winfo_toplevel() top.quit() main = Tkclass() 实例并正确设置变量。

这是一个简短的示例程序来说明这个想法。

{{1}}