paint-brush
使用 Tkinter 构建您的第一个 Python GUI经过@pictureinthenoise
7,964 讀數
7,964 讀數

使用 Tkinter 构建您的第一个 Python GUI

经过 Picture in the Noise13m2022/11/14
Read on Terminal Reader
Read this story w/o Javascript

太長; 讀書

Tkinter 是 Python 构建 GUI 的标准,包含在 Python 标准库中。本指南通过一个简单的 GUI 应用程序的设计来解释基本的 Tkinter 概念,包括 GUI 元素的布局、捕获用户输入以及将 GUI 元素绑定到回调方法。

People Mentioned

Mention Thumbnail
featured image - 使用 Tkinter 构建您的第一个 Python GUI
Picture in the Noise HackerNoon profile picture

介绍

也许您刚刚开始学习 Python,并且已经构建了一两个简单的应用程序。恭喜!但是,现在呢?那么,如何构建一个图形用户界面(“GUI”)来与您闪亮的新 Python 应用程序交互?


使用 Python 构建 GUI 应用程序有多种选择,包括PyQtwxPython 。然而,本指南将向您介绍Tkinter


Tkinter代表“Tk 接口”,是 Python 构建 GUI 的标准,包含在Python 标准库中。它是Tk GUI 工具包的绑定,这是一个免费的开源 GUI小部件库,可用于以各种编程语言构建图形界面。


本教程介绍了一个基本 GUI 应用程序的设计,该应用程序在用户选择的时区中显示本地时间。这些步骤逐步构建应用程序并描述了使用Tkinter时的一些关键概念,包括 GUI 元素的布局、捕获用户输入以及将 GUI 元素绑定到回调方法。


先决条件

要完成本指南,您需要具备:


  • 安装了 Python
  • 安装pip
  • 安装了pytz时区库。该库可以使用pip安装。


 pip install pytz


本指南将交替使用术语根窗口主窗口


第 1 步 - 创建一个新的 Python 应用程序并设置所需的导入

创建一个名为timezone.py的新 Python 应用程序并添加以下import语句以导入Tkinterdatetimepytz模块。


 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 类的实例

实例化Tk类会创建一个根窗口,它将作为时区应用程序 GUI 的主窗口。


 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 - 计算主窗口中心位置

主窗口可以放置在屏幕上的任何位置,例如中心、左上角等。居中的窗口提供了一个漂亮的“外观”,并且可以使用根窗口的winfo_screenwidth()确定主窗口的中心位置winfo_screenwidth()winfo_screenheight()方法以及一些简单的数学运算。这两种方法返回屏幕宽度和屏幕高度,用于计算适当的 (x,y) 坐标以使主窗口居中。与窗口宽度和高度一样,中心位置值也可以分配给变量以使代码更具可读性。


 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_xcenter_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方法按顺序接受heightwidth参数。任一参数的True或非零值指定主窗口可沿相关轴调整大小。任一参数的False0值指定主窗口不能沿给定轴调整大小。计时器应用程序将对高度和宽度使用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 种方式排列:


  1. 使用pack()方法打包pack()几何管理器在将小部件添加到根窗口或父小部件之前将它们组织成块。考虑包装的一种不完美但可能有用的方法是考虑将杂货物品添加到杂货袋中。这些物品不一定要添加到包中的预定义位置。相反,它们是一个接一个地包装,用尽可用空间,直到所有物品都放入包中。 pack()几何管理器以类似的方式工作。

  2. 使用place()方法放置place()几何管理器小部件放置到根窗口或父小部件中特定的预定义位置。在构建精确的 GUI 布局时,这个几何管理器显然很有用。

  3. 使用grid()方法排列为格。网格是二维行/列表。通过指定应放置小部件的特定行和列,将小部件添加到网格中。使用根窗口的columnconfigurerowconfigure方法设置网格。这些方法中的每一个都有一个index和一个weight属性。 index属性使用起始基0指定列或行的位置。 weight属性指定特定列或行相对于其他列的大小。例如,如果第0 列的权重为1 ,第 1的权重为3 ,则第 1 列将是第0 列的 3 倍。


将元素彼此相邻放置时,网格很方便,而且实现起来相对简单。时区应用程序将使用划分为 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 的LabelButton小部件与它们的名称完全相同。 Label小部件允许程序员显示文本(即标签),而Button小部件用于显示按钮。 Listbox小部件用于从选项列表中选择一个(或多个)值。

当然,除了上面列出的 3 个小部件之外,还有其他小部件,例如SpinBoxEntryMessage小部件。正式的Tk 命令文档是一个有用的资源,可以帮助您了解更多关于 Tk 工具包中可用的小部件的信息。

步骤 6a - 创建小部件

为与 GUI 设计一起使用的给定小部件创建每个小部件类的实例。时区应用程序使用 4 个小部件实例:2 个Label小部件、1 个Listbox小部件和 1 个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="")


如上面的代码块所示,每个小部件实例都“附加”到root窗口。 Listbox小部件还需要一个特殊的 Tkinter Variable()类的实例化,该类用于为小部件提供时区选项列表,用户可以通过Listbox listvariable属性从中选择。每个Label小部件显示的文本可以使用text属性进行配置。 time_label的文本值留空,因为每次用户“获取”所选时区的时间时都会动态设置它。

步骤 6b - 在网格上放置小部件

步骤 5a 中创建的小部件实例可以使用grid()方法放置在步骤 4 中定义的网格上。时区应用程序将使用以下grid()方法属性来定义布局:


  • column :指定将使用0基础放置小部件的特定列。

  • row :指定将使用0放置小部件的特定行。

  • columnspan :指定小部件应跨越指定数量的列。例如,具有columnspan=3值的小部件将跨越 3 列,即使小部件本身小于 3 列。

  • sticky :Tkinter 的默认行为是将一个小部件放置在它所在的单元格的水平和垂直中心(即特定的行/列位置)。可以使用sticky属性覆盖此默认行为,该属性使用类似指南针的值,包括NWNNEWESWSSE ,以将小部件对齐到小部件单元格的特定位置。例如, sticky=tK.W指定小部件应与其网格单元的西角对齐。类似地, sticky=tK.E指定小部件应与其网格单元的东角对齐。

  • padxpadypadxpady属性分别用于添加 x 轴和 y 轴填充,其值以像素为单位。自然地,填充可以提供更专业的 GUI,确保小部件不会直接“碰撞”到根窗口或其他小部件的边缘。


 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_listboxtime_label小部件作为回调参数。这些回调参数实际上是不必要的,因为select_timezone_listboxtime_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 步 - 完成并运行应用程序

根窗口的mainloop()方法作为最后一行代码应用。 mainloop()方法将无限循环运行 GUI,直到用户退出。


完成的代码如下:


 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 应如下所示:




要使用该应用程序,请单击列表框并使用键盘的上/下光标键滚动浏览时区选项。单击获取时间按钮以显示所选时区的当前时间。




下一步

恭喜您使用Tkinter构建了您的第一个 Python GUI 应用程序!如简介中所述,本指南旨在向您介绍一些基本概念。前面提到的Python 标准库文档Tk 命令文档参考是两个很好的资源,可帮助您了解更高级的 Tkinter 特性和功能。


Tkinter GUI 应用程序有时被批评为具有非本地外观。这可能是真的。但是工具包小部件是高度可配置的,并且可以相对快速地构建 Tkinter GUI 应用程序,而无需安装任何外部 Python 包。


除了正式的文档之外,还有无数的教程可以通过 Internet 来了解如何使用 Tkinter 构建更复杂的 GUI 应用程序。