我已经看到了设置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()
答案 0 :(得分:26)
我更喜欢*的选项是继承Tk类。我认为这是更合理的选择,因为窗口实际上是您的应用程序。继承Frame
对我来说没有任何意义,那么继承自Button
或Canvas
或Label
。由于您只能拥有一个根,因此您继承的是有意义的。
我还认为,如果您导入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 answer的Python 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.IntVar
,Tkinter.StringVar
和Tkinter.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}}