介绍 也许您刚刚开始学习 Python,并且已经构建了一两个简单的应用程序。恭喜!但是,现在呢?那么,如何构建一个图形用户界面(“GUI”)来与您闪亮的新 Python 应用程序交互? 使用 Python 构建 GUI 应用程序有多种选择,包括 和 。然而,本指南将向您介绍 。 PyQt wxPython Tkinter 代表“Tk 接口”,是 Python 构建 GUI 的标准,包含在 中。它是 的绑定,这是一个免费的开源 GUI 库,可用于以各种编程语言构建图形界面。 Tkinter Python 标准库 Tk GUI 工具包 小部件 本教程介绍了一个基本 GUI 应用程序的设计,该应用程序在用户选择的时区中显示本地时间。这些步骤逐步构建应用程序并描述了使用 时的一些关键概念,包括 GUI 元素的布局、捕获用户输入以及将 GUI 元素绑定到回调方法。 Tkinter 先决条件 要完成本指南,您需要具备: 。 安装了 Python 安装 。 pip 安装了 时区库。该库可以使用 安装。 pytz pip pip install pytz 本指南将交替使用术语 和 。 根窗口 主窗口 第 1 步 - 创建一个新的 Python 应用程序并设置所需的导入 创建一个名为 的新 Python 应用程序并添加以下 语句以导入 、 和 模块。 timezone.py import Tkinter datetime pytz import tkinter as tk import datetime import pytz 第 2 步 - 添加时区 本指南包含一组美国时区,它们只是 支持的时区的一小部分。可以通过添加额外的 时区名称来扩展应用程序的功能。可以通过运行以下命令输出 可用时区的完整列表: pytz pytz pytz print(pytz.all_timezones) 通过 可用的美国时区集被指定为一个列表。 pytz import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] 第 3 步 - 创建 Tk 类的实例 实例化 类会创建一个 ,它将作为时区应用程序 GUI 的主窗口。 Tk 根窗口 import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() 第 4 步 - 设置主窗口 此步骤配置根窗口,特别是它的标题、几何形状和可调整大小。 步骤 4a - 设置主窗口标题 窗口标题是使用 方法设置的。 title import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") 步骤 4b - 设置主窗口的宽度和高度 以像素表示的窗口宽度和高度值可以分配给变量,以使代码更易于理解。 import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 步骤 4c - 计算主窗口中心位置 主窗口可以放置在屏幕上的任何位置,例如中心、左上角等。居中的窗口提供了一个漂亮的“外观”,并且可以使用根窗口的 确定主窗口的中心位置 和 方法以及一些简单的数学运算。这两种方法返回屏幕宽度和屏幕高度,用于计算适当的 (x,y) 坐标以使主窗口居中。与窗口宽度和高度一样,中心位置值也可以分配给变量以使代码更具可读性。 winfo_screenwidth() winfo_screenwidth() winfo_screenheight() import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) 请注意, 和 值也以像素表示,并且 用于确保两个计算值都是整数。 center_x center_y int 步骤 4d - 设置主窗口几何图形 窗口几何,它指定主窗口的大小和位置,是使用根窗口的 方法设置的。为简单起见,您可以使用格式化的字符串文字或 ,它将在运行时插入几何变量表达式。根据以下代码块,将 文字作为参数传递给 方法。 root geometry f-string f 字符串 geometry import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}") 步骤 4e - 设置主窗口可调整大小 根窗口沿其 x 和 y 轴的可调整大小可以通过根窗口的 方法设置。 方法按顺序接受 和 参数。任一参数的 或非零值指定主窗口可沿相关轴调整大小。任一参数的 或 值指定主窗口不能沿给定轴调整大小。计时器应用程序将对高度和宽度使用 值,以防止调整主窗口的大小。 resizable resizable height width True False 0 False import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}") root.resizable(False, False) 第 5 步 - 为小部件布局指定网格 可以使用 以不同的方式将 排列在主窗口的顶部。通常,小部件可以按 3 种方式排列: 几何管理器 小部件 使用 方法 。 几何管理器在将小部件添加到根窗口或父小部件之前将它们组织成块。考虑 的一种不完美但可能有用的方法是考虑将杂货物品添加到杂货袋中。这些物品不一定要添加到包中的预定义位置。相反,它们是一个接一个地 ,用尽可用空间,直到所有物品都放入包中。 几何管理器以类似的方式工作。 pack() 打包 pack() 包装 包装 pack() 使用 方法 。 几何管理器 小部件放置到根窗口或父小部件中特定的预定义位置。在构建精确的 GUI 布局时,这个几何管理器显然很有用。 place() 放置 place() 将 使用 方法排列为 格。网格是二维行/列表。通过指定应放置小部件的特定行和列,将小部件添加到网格中。使用根窗口的 和 方法设置网格。这些方法中的每一个都有一个 和一个 属性。 属性使用起始基 指定列或行的位置。 属性指定特定列或行相对于其他列的大小。例如,如果第 的权重为 ,第 1 的权重为 ,则 将是第 的 3 倍。 grid() 网 columnconfigure rowconfigure index weight index 0 weight 0 列 1 列 3 第 1 列 0 列 将元素彼此相邻放置时,网格很方便,而且实现起来相对简单。时区应用程序将使用划分为 4 个相等列的主窗口网格。 import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}") root.resizable(False, False) root.columnconfigure(0, weight=1) root.columnconfigure(1, weight=1) root.columnconfigure(2, weight=1) root.columnconfigure(3, weight=1) 第 6 步 - 添加小部件 在这一步中,小部件被添加到步骤 4 中定义的主窗口网格中。时区应用程序将使用 3 个 小部件: TKinter Label Listbox Button Tkinter 的 和 小部件与它们的名称完全相同。 小部件允许程序员显示文本(即标签),而 小部件用于显示按钮。 小部件用于从选项列表中选择一个(或多个)值。 Label Button Label Button Listbox 当然,除了上面列出的 3 个小部件之外,还有其他小部件,例如 、 和 小部件。正式的 是一个有用的资源,可以帮助您了解更多关于 Tk 工具包中可用的小部件的信息。 SpinBox Entry Message Tk 命令文档 步骤 6a - 创建小部件 为与 GUI 设计一起使用的给定小部件创建每个小部件类的实例。时区应用程序使用 4 个小部件实例:2 个 小部件、1 个 小部件和 1 个 小部件。 Label Listbox Button import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}") root.resizable(False, False) root.columnconfigure(0, weight=1) root.columnconfigure(1, weight=1) root.columnconfigure(2, weight=1) root.columnconfigure(3, weight=1) # Instance of Label widget class for selection prompt. select_timezone_label = tk.Label(root, text="Please select a timezone.") # Instance of Listbox class for selection of timezone from list. list_var = tk.Variable(value=timezones) select_timezone_listbox = tk.Listbox(root, listvariable=list_var, height=1) # Instance of Button class to get the local time in the selected timezone. select_timezone_button = tk.Button(root, text="Get Time") # Second instance of the Label class to display the local time in the selected timezone. time_label = tk.Label(root, text="") 如上面的代码块所示,每个小部件实例都“附加”到 窗口。 小部件还需要一个特殊的 Tkinter 类的实例化,该类用于为小部件提供时区选项列表,用户可以通过 属性从中选择。每个 小部件显示的文本可以使用 属性进行配置。 的文本值留空,因为每次用户“获取”所选时区的时间时都会动态设置它。 root Listbox Variable() Listbox listvariable Label text time_label 步骤 6b - 在网格上放置小部件 步骤 5a 中创建的小部件实例可以使用 方法放置在步骤 4 中定义的网格上。时区应用程序将使用以下 方法属性来定义布局: grid() grid() :指定将使用 基础放置小部件的特定列。 column 0 :指定将使用 放置小部件的特定行。 row 0 :指定小部件应跨越指定数量的列。例如,具有 值的小部件将跨越 3 列,即使小部件本身小于 3 列。 columnspan columnspan=3 :Tkinter 的默认行为是将一个小部件放置在它所在的单元格的水平和垂直中心(即特定的行/列位置)。可以使用 属性覆盖此默认行为,该属性使用类似指南针的值,包括 、 、 、 、 、 、 和 ,以将小部件对齐到小部件单元格 的特定位置。例如, 指定小部件应与其网格单元的西角对齐。类似地, 指定小部件应与其网格单元的东角对齐。 sticky sticky NW N NE W E SW S SE 内 sticky=tK.W sticky=tK.E , : 和 属性分别用于添加 x 轴和 y 轴填充,其值以像素为单位。自然地,填充可以提供更专业的 GUI,确保小部件不会直接“碰撞”到根窗口或其他小部件的边缘。 padx pady padx pady import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}") root.resizable(False, False) root.columnconfigure(0, weight=1) root.columnconfigure(1, weight=1) root.columnconfigure(2, weight=1) root.columnconfigure(3, weight=1) # Instance of Label widget class for selection prompt. select_timezone_label = tk.Label(root, text="Please select a timezone.") # Instance of Listbox class for selection of timezone from list. list_var = tk.Variable(value=timezones) select_timezone_listbox = tk.Listbox(root, listvariable=list_var, height=1) # Instance of Button class to get the local time in the selected timezone. select_timezone_button = tk.Button(root, text="Get Time") # Second instance of the Label class to display the local time in the selected timezone. time_label = tk.Label(root, text="") # Place widgets on grid. select_timezone_label.grid(column=0, row=0, columnspan=4, sticky=tk.W, padx=10, pady=10) select_timezone_listbox.grid(column=0, row=1, columnspan=3, sticky=tk.EW, padx=10, pady=10) select_timezone_button.grid(column=4, row=1, sticky=tk.E, padx=10, pady=10) time_label.grid(column=0, row=4, columnspan=4, sticky=tk.W, padx=10, pady=10) 第 7 步 - 创建获取时间按钮回调方法 当用户单击第 5 步中创建的 按钮时,需要定义一个回调方法来处理事件。 select_timezone_button 步骤 7a - 绑定获取时间按钮 在定义回调逻辑之前,首先将按钮绑定到最终将包含回调代码的方法名称会很有帮助。 方法可以与 函数结合使用,将 绑定到指定的回调方法。另外,请注意 函数用于将引用传递给 和 小部件作为回调参数。这些回调参数实际上是 的,因为 和 在全局范围内。但是,演示如何将参数传递给回调函数可以说是有用的。 bind() lambda select_timezone_button lambda select_timezone_listbox time_label 不必要 select_timezone_listbox time_label import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}") root.resizable(False, False) root.columnconfigure(0, weight=1) root.columnconfigure(1, weight=1) root.columnconfigure(2, weight=1) root.columnconfigure(3, weight=1) # Instance of Label widget class for selection prompt. select_timezone_label = tk.Label(root, text="Please select a timezone.") # Instance of Listbox class for selection of timezone from list. list_var = tk.Variable(value=timezones) select_timezone_listbox = tk.Listbox(root, listvariable=list_var, height=1) # Instance of Button class to get the local time in the selected timezone. select_timezone_button = tk.Button(root, text="Get Time") # Second instance of the Label class to display the local time in the selected timezone. time_label = tk.Label(root, text="") # Place widgets on grid. select_timezone_label.grid(column=0, row=0, columnspan=4, sticky=tk.W, padx=10, pady=10) select_timezone_listbox.grid(column=0, row=1, columnspan=3, sticky=tk.EW, padx=10, pady=10) select_timezone_button.grid(column=4, row=1, sticky=tk.E, padx=10, pady=10) time_label.grid(column=0, row=4, columnspan=4, sticky=tk.W, padx=10, pady=10) select_timezone_button.bind("<Button>", lambda e, args=[select_timezone_listbox, time_label]: get_timezone_time(e, args)) 步骤 7b - 定义回调逻辑 处理按钮点击事件的回调逻辑定义如下。 def get_timezone_time(e, args): select_timezone_listbox = args[0] time_label = args[1] selection_index = select_timezone_listbox.curselection() selected_timezone = select_timezone_listbox.get(selection_index) now_time = datetime.datetime.now() tz_time = now_time.astimezone(pytz.timezone(selected_timezone)) tz_formatted = tz_time.strftime("%H:%M:%S") time_label.configure({"text": f"The time in {selected_timezone} is {tz_formatted}."}) time_label.update() 和 方法用于从对 小部件的引用中检索用户选择的时区。然后将用户的当前时间转换为选定的时区时间。最后,使用 方法将 引用的 属性更改为所选时区的本地时间。请注意, 方法用于“强制” 小部件使用新的文本值更新自身。 curselection() get() select_timezone_listbox configure time_label text update() time_label 第 8 步 - 完成并运行应用程序 根窗口的 方法作为最后一行代码应用。 方法将无限循环运行 GUI,直到用户退出。 mainloop() mainloop() 完成的代码如下: import tkinter as tk import datetime import pytz timezones = ["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", "US/Hawaii", "US/Indiana-Starke", "US/Michigan", "US/Mountain", "US/Pacific", "US/Samoa"] def get_timezone_time(e, args): select_timezone_listbox = args[0] time_label = args[1] selection_index = select_timezone_listbox.curselection() selected_timezone = select_timezone_listbox.get(selection_index) now_time = datetime.datetime.now() tz_time = now_time.astimezone(pytz.timezone(selected_timezone)) tz_formatted = tz_time.strftime("%H:%M:%S") time_label.configure({"text": f"The time in {selected_timezone} is {tz_formatted}."}) time_label.update() root = tk.Tk() root.title("Simple Timezone Application") window_width = 450 window_height = 175 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() center_x = int((screen_width - window_width)/2) center_y = int((screen_height - window_height)/2) root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}") root.resizable(False, False) root.columnconfigure(0, weight=1) root.columnconfigure(1, weight=1) root.columnconfigure(2, weight=1) root.columnconfigure(3, weight=1) # Instance of Label widget class for selection prompt. select_timezone_label = tk.Label(root, text="Please select a timezone.") # Instance of Listbox class for selection of timezone from list. list_var = tk.Variable(value=timezones) select_timezone_listbox = tk.Listbox(root, listvariable=list_var, height=1) # Instance of Button class to get the local time in the selected timezone. select_timezone_button = tk.Button(root, text="Get Time") # Second instance of the Label class to display the local time in the selected timezone. time_label = tk.Label(root, text="") # Place widgets on grid. select_timezone_label.grid(column=0, row=0, columnspan=4, sticky=tk.W, padx=10, pady=10) select_timezone_listbox.grid(column=0, row=1, columnspan=3, sticky=tk.EW, padx=10, pady=10) select_timezone_button.grid(column=4, row=1, sticky=tk.E, padx=10, pady=10) time_label.grid(column=0, row=4, columnspan=4, sticky=tk.W, padx=10, pady=10) # Bind button to callback. select_timezone_button.bind("<Button>", lambda e, args=[select_timezone_listbox, time_label]: get_timezone_time(e, args)) root.mainloop() 启动应用程序后,GUI 应如下所示: 要使用该应用程序,请单击列表框并使用键盘的上/下光标键滚动浏览时区选项。单击 按钮以显示所选时区的当前时间。 获取时间 下一步 恭喜您使用 构建了您的第一个 Python GUI 应用程序!如简介中所述,本指南旨在向您介绍一些基本概念。前面提到的 和 参考是两个很好的资源,可帮助您了解更高级的 Tkinter 特性和功能。 Tkinter Python 标准库文档 Tk 命令文档 Tkinter GUI 应用程序有时被批评为具有非本地外观。这可能是真的。但是工具包小部件是高度可配置的,并且可以相对快速地构建 Tkinter GUI 应用程序,而无需安装任何外部 Python 包。 除了正式的文档之外,还有无数的教程可以通过 Internet 来了解如何使用 Tkinter 构建更复杂的 GUI 应用程序。