一、说明
        在本教程中,您将学习如何在 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 类并在根窗口中使用子类。
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上使用面向对象的编程方法,更多的和更需要掌握的是消息原理。在系列文章的下篇我们将集中阐述事件和绑定问题。










