一、说明
在本教程中,您将学习如何在 Tkinter 中应用面向对象编程以使代码更有条理。首先介绍Tk下小部件,然后介绍Ttk小部件,即如何从ttk.Frame
类继承并在根窗口中使用它。
二、定义 Tkinter 面向对象的窗口
2.1 最基本的对象
以下简单程序创建一个根窗口并将其显示在屏幕上:
import tkinter as tk
root = tk.Tk()
root.mainloop()
当程序变得越来越复杂时,可以使用面向对象的编程方法使代码更有条理。
下面的程序实现与上面的程序相同的结果,但使用 aclass
代替:
import tkinter as tkclass 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 showinfoclass App(tk.Tk):def __init__(self):super().__init__()# configure the root windowself.title('My Awesome App')self.geometry('300x50')# labelself.label = ttk.Label(self, text='Hello, Tkinter!')self.label.pack()# buttonself.button = ttk.Button(self, text='Click Me')self.button['command'] = self.button_clickedself.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}# labelself.label = ttk.Label(self, text='Hello, Tkinter!')self.label.pack(**options)# buttonself.button = ttk.Button(self, text='Click Me')self.button['command'] = self.button_clickedself.button.pack(**options)# show the frame on the containerself.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 windowself.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 showinfoclass MainFrame(ttk.Frame):def __init__(self, container):super().__init__(container)options = {'padx': 5, 'pady': 5}# labelself.label = ttk.Label(self, text='Hello, Tkinter!')self.label.pack(**options)# buttonself.button = ttk.Button(self, text='Click Me')self.button['command'] = self.button_clickedself.button.pack(**options)# show the frame on the containerself.pack(**options)def button_clicked(self):showinfo(title='Information',message='Hello, Tkinter!')class App(tk.Tk):def __init__(self):super().__init__()# configure the root windowself.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 ttkclass InputFrame(ttk.Frame):def __init__(self, container):super().__init__(container)# setup the grid layout managerself.columnconfigure(0, weight=1)self.columnconfigure(0, weight=3)self.__create_widgets()def __create_widgets(self):# Find whatttk.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 checkboxmatch_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 checkboxwrap_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 managerself.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 windowself.columnconfigure(0, weight=4)self.columnconfigure(1, weight=1)self.__create_widgets()def __create_widgets(self):# create the input frameinput_frame = InputFrame(self)input_frame.grid(column=0, row=0)# create the button framebutton_frame = ButtonFrame(self)button_frame.grid(column=1, row=0)if __name__ == "__main__":app = App()app.mainloop()
3.4 小结
- 子类化并初始化框架上的小部件。
ttk.Frame
- 在根窗口中使用 的子类。
ttk.Frame
四、总结
本文阐述了如何在Tkinter上使用面向对象的编程方法,更多的和更需要掌握的是消息原理。在系列文章的下篇我们将集中阐述事件和绑定问题。