一、说明
在本教程中,您将学习如何在 Tkinter 中应用面向对象编程以使代码更有条理。首先介绍Tk下小部件,然后介绍Ttk小部件,即如何从ttk.Frame
类继承并在根窗口中使用它。
二、定义 Tkinter 面向对象的窗口
2.1 最基本的对象
以下简单程序创建一个根窗口并将其显示在屏幕上:
import tkinter as tk
root = tk.Tk()
root.mainloop()
当程序变得越来越复杂时,可以使用面向对象的编程方法使代码更有条理。
下面的程序实现与上面的程序相同的结果,但使用 aclass
代替:
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
if __name__ == "__main__":
app = App()
app.mainloop()
怎么运行的。
- 首先,定义一个
App
类,继承该类tk.Tk
。在方法内部__init__()
,调用类__init__()
的方法tk.Tk
。 - 其次,创建该类的新实例
App
并调用该mainloop()
方法来显示根窗口。
2.2 Tkinter 中面向对象窗口的另一个示例
下面的类表示一个由标签和按钮组成的窗口。当您单击该按钮时,程序会显示一个消息框:
import tkinter as tk
from tkinter import ttk
from tkinter.messagebox import showinfo
class App(tk.Tk):
def __init__(self):
super().__init__()
# configure the root window
self.title('My Awesome App')
self.geometry('300x50')
# label
self.label = ttk.Label(self, text='Hello, Tkinter!')
self.label.pack()
# button
self.button = ttk.Button(self, text='Click Me')
self.button['command'] = self.button_clicked
self.button.pack()
def button_clicked(self):
showinfo(title='Information', message='Hello, Tkinter!')
if __name__ == "__main__":
app = App()
app.mainloop()
它的工作原理。
- 首先,在
__init__()
App类的方法中创建一个标签和按钮。 - 其次,将
button_clicked()
方法分配给按钮的命令选项。在该button_clicked()
方法内,显示一个消息框。 - 第三,将应用程序引导移至该
if __name__ = "main"
块。
2.3 小结
- 使用面向对象的编程方法使代码更有条理。
- 定义一个类,继承该类
tk.Tk
。始终super().__init__()
在子类中从父类调用 。
三、关于Ttk的原理
上面您学习了如何对类进行子类化。但是,一个 Tkinter 应用程序应该只有一个实例。 因此,从 ttk 继承是很常见的。Frame 类并在根窗口中使用子类。
ttk介绍: 是增强版的tk,其中有17个图形类,包括tk中的11个类:
Button, Checkbutton, Entry, Frame, Label, LabelFrame, Menubutton, PanedWindow, Radiobutton, Scale, Scrollbar
ttk新增的6个: Combobox, Notebook, Progressbar, Separator, Sizegrip, Treeview
这17个类都继承自 Widget。
3.2 ttk,Frame继承和实例化
若要继承该类,请使用以下语法:ttk.Frame
class MainFrame(ttk.Frame):
pass
由于 Frame 需要一个容器,因此您需要向其 __init__() 方法添加一个参数,并调用 ttk.Frame 类的 __init__() 方法,如下所示:
class MainFrame(ttk.Frame):
def __init__(self, container):
super().__init__(container)
下面显示了具有标签和按钮的完整类。单击该按钮时,它会显示一个消息框:MainFrame
class MainFrame(ttk.Frame):
def __init__(self, container):
super().__init__(container)
options = {'padx': 5, 'pady': 5}
# label
self.label = ttk.Label(self, text='Hello, Tkinter!')
self.label.pack(**options)
# button
self.button = ttk.Button(self, text='Click Me')
self.button['command'] = self.button_clicked
self.button.pack(**options)
# show the frame on the container
self.pack(**options)
def button_clicked(self):
showinfo(title='Information',
message='Hello, Tkinter!')
下面定义了一个继承自Tk
类的类:App
class App(tk.Tk):
def __init__(self):
super().__init__()
# configure the root window
self.title('My Awesome App')
self.geometry('300x100')
您可以通过块引导应用程序。if __name__ == "__main__"
if __name__ == "__main__":
app = App()
frame = MainFrame(app)
app.mainloop()
在此代码中:
- 首先,创建该类的新实例。
App
- 其次,创建类的新实例,并将其容器设置为应用实例。
MainFrame
- 第三,通过调用 app() 启动应用程序。它将执行将调用根窗口的方法。
__call__()
mainloop()
把它们放在一起:
import tkinter as tk
from tkinter import ttk
from tkinter.messagebox import showinfo
class MainFrame(ttk.Frame):
def __init__(self, container):
super().__init__(container)
options = {'padx': 5, 'pady': 5}
# label
self.label = ttk.Label(self, text='Hello, Tkinter!')
self.label.pack(**options)
# button
self.button = ttk.Button(self, text='Click Me')
self.button['command'] = self.button_clicked
self.button.pack(**options)
# show the frame on the container
self.pack(**options)
def button_clicked(self):
showinfo(title='Information',
message='Hello, Tkinter!')
class App(tk.Tk):
def __init__(self):
super().__init__()
# configure the root window
self.title('My Awesome App')
self.geometry('300x100')
if __name__ == "__main__":
app = App()
frame = MainFrame(app)
app.mainloop()
输出:
3.3 更多面向对象框架示例
下面的示例使用这些类从“框架”教程转换“替换”窗口:
import tkinter as tk
from tkinter import ttk
class InputFrame(ttk.Frame):
def __init__(self, container):
super().__init__(container)
# setup the grid layout manager
self.columnconfigure(0, weight=1)
self.columnconfigure(0, weight=3)
self.__create_widgets()
def __create_widgets(self):
# Find what
ttk.Label(self, text='Find what:').grid(column=0, row=0, sticky=tk.W)
keyword = ttk.Entry(self, width=30)
keyword.focus()
keyword.grid(column=1, row=0, sticky=tk.W)
# Replace with:
ttk.Label(self, text='Replace with:').grid(
column=0, row=1, sticky=tk.W)
replacement = ttk.Entry(self, width=30)
replacement.grid(column=1, row=1, sticky=tk.W)
# Match Case checkbox
match_case = tk.StringVar()
match_case_check = ttk.Checkbutton(
self,
text='Match case',
variable=match_case,
command=lambda: print(match_case.get()))
match_case_check.grid(column=0, row=2, sticky=tk.W)
# Wrap Around checkbox
wrap_around = tk.StringVar()
wrap_around_check = ttk.Checkbutton(
self,
variable=wrap_around,
text='Wrap around',
command=lambda: print(wrap_around.get()))
wrap_around_check.grid(column=0, row=3, sticky=tk.W)
for widget in self.winfo_children():
widget.grid(padx=0, pady=5)
class ButtonFrame(ttk.Frame):
def __init__(self, container):
super().__init__(container)
# setup the grid layout manager
self.columnconfigure(0, weight=1)
self.__create_widgets()
def __create_widgets(self):
ttk.Button(self, text='Find Next').grid(column=0, row=0)
ttk.Button(self, text='Replace').grid(column=0, row=1)
ttk.Button(self, text='Replace All').grid(column=0, row=2)
ttk.Button(self, text='Cancel').grid(column=0, row=3)
for widget in self.winfo_children():
widget.grid(padx=0, pady=3)
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title('Replace')
self.geometry('400x150')
self.resizable(0, 0)
# windows only (remove the minimize/maximize button)
self.attributes('-toolwindow', True)
# layout on the root window
self.columnconfigure(0, weight=4)
self.columnconfigure(1, weight=1)
self.__create_widgets()
def __create_widgets(self):
# create the input frame
input_frame = InputFrame(self)
input_frame.grid(column=0, row=0)
# create the button frame
button_frame = ButtonFrame(self)
button_frame.grid(column=1, row=0)
if __name__ == "__main__":
app = App()
app.mainloop()
3.4 小结
- 子类化并初始化框架上的小部件。
ttk.Frame
- 在根窗口中使用 的子类。
ttk.Frame
四、总结
本文阐述了如何在Tkinter上使用面向对象的编程方法,更多的和更需要掌握的是消息原理。在系列文章的下篇我们将集中阐述事件和绑定问题。