index
- 在 Windows 上安装 Tk
- 第一个(真实的)例子
- 设计
- 代码
- 设置主应用程序窗口
- 创建内容框架
- 创建输入框小部件
- 创建剩余的小部件
- 添加一些设置
- 执行计算
- 启动事件循环
- 还有一件事...
在 Windows 上安装 Tk
在 Windows 上安装 Tk for Python (Tkinter)
Tkinter(以及自 Python 3.1 起,ttk是新主题小部件的接口)包含在 Python 标准库中。
安装或编译 Python 后,对其进行测试以确保 Tkinter 正常工作。在 Python 提示符下,输入以下两个命令:
>>> import tkinter
>>> tkinter._test()
这应该会弹出一个小窗口;窗口顶部的第一行应该说“这是 Tcl/Tk 8.6 版”;确保它不是 8.4 或 8.5!
得到一个错误说"No module named tkinter"
?您可能正在使用 Python 2。本教程假设 Python 3。
您还可以获得正在使用的 Tcl/Tk 的确切版本:
>>> tkinter.Tcl().eval('info patchlevel')
'8.6.9'
它应该返回类似“8.6.9”的内容。
第一个(真实的)例子
顺便说一下,让我们尝试一个更实际的例子,它会让您初步了解真实 Tk 程序背后的代码是什么样的。
设计
我们将创建一个简单的 GUI 工具,将英尺的距离转换为米的等效距离。如果我们将其勾勒出来,它可能看起来像这样:
我们的英尺到米转换程序的草图。
所以看起来我们有一个简短的文本输入小部件,可以让我们输入英尺数。“计算”按钮将从该条目中获取值,执行计算,并将结果放在条目下方的标签中。我们还有三个静态标签(“英尺”、“相当于”和“米”),它们可以帮助我们的用户弄清楚如何运行应用程序。
接下来我们需要做的是查看布局。我们包含的小部件似乎很自然地分成了一个三列三行的网格。在布局上,事情似乎很自然地分为三列三行,如下图:
我们的用户界面布局,遵循 3 x 3 网格。
代码
现在这里是使用 Tkinter 创建整个应用程序所需的 Python 代码。
from tkinter import * # tkinter的标准绑定,加载Tk库
from tkinter import ttk # ttk是它的子模块,是添加到Tk的较新的“小部件”
def calculate(*args):
try:
value = float(feet.get())
meters.set(int(0.3048 * value * 10000.0 + 0.5)/10000.0)
except ValueError:
pass
root = Tk() #设置主程序窗口
root.title("Feet to Meters") #设置主程序窗口标题
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
feet = StringVar()
feet_entry = ttk.Entry(mainframe, width=7, textvariable=feet)
feet_entry.grid(column=2, row=1, sticky=(W, E))
meters = StringVar()
ttk.Label(mainframe, textvariable=meters).grid(column=2, row=2, sticky=(W, E))
ttk.Button(mainframe, text="Calculate", command=calculate).grid(column=3, row=3, sticky=W)
ttk.Label(mainframe, text="feet").grid(column=3, row=1, sticky=W)
ttk.Label(mainframe, text="is equivalent to").grid(column=1, row=2, sticky=E)
ttk.Label(mainframe, text="meters").grid(column=3, row=2, sticky=W)
for child in mainframe.winfo_children():
child.grid_configure(padx=5, pady=5)
feet_entry.focus()
root.bind("<Return>", calculate)
root.mainloop()
设置主应用程序窗口
接下来,以下代码设置主应用程序窗口,为其命名为“英尺到米”。
root = Tk()
root.title("Feet to Meters")
创建内容框架
接下来,我们创建一个框架小部件,它将保存我们用户界面的内容。
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
为什么我们在主窗口内放置一个框架?严格来说,在较旧的 Tk 程序中,我们可以将界面中的其他小部件直接放入主应用程序窗口,而无需插入内容框架。
但是,主窗口本身并不是较新的“主题”小部件的一部分。它的背景颜色与我们将放入其中的主题小部件不匹配。使用“主题”框架小部件来保存内容可确保背景正确。这如下图所示。
在窗口内放置一个主题框架。
创建输入框小部件
我们将创建的第一个小部件是可以输入要转换的英尺数的输入框。
feet = StringVar()
feet_entry = ttk.Entry(mainframe, width=7, textvariable=feet)
feet_entry.grid(column=2, row=1, sticky=(W, E))
我们需要做两件事:创建小部件本身,然后将其放置在屏幕上。
当我们创建一个小部件时,我们需要指定它的parent,即这个小部件将被放置在哪个小部件中。在这种情况下,我们希望将输入框放置在内容框架内。我们在内容框架中创建其他部件,称为内容框架的child。在 Python 中,当实例化小部件对象时,parent将作为第一个参数传递。
当我们创建一个小部件时,我们可以选择为其提供某些配置选项。在这里,我们指定条目出现的宽度,即 7 个字符。我们还赋予它一个神秘的textvariable
;我们很快就会看到它的作用。
创建小部件时,它们不会自动显示在屏幕上,因为 Tk 不知道您希望它们相对于其他小部件如何放置。这就是grid
的作用。还记得我们绘制应用程序时的布局网格吗?小部件放置在适当的列(1、2 或 3)和行(也是 1、2 或 3)中。
sticky
选项规定了如何在小部件网格单元内排列。它使用罗盘方向,w
(west) 意味着将小部件锚定到单元格的左侧,we
(west-east) 意味着将其附加到左侧和右侧,依此类推。Python 还为这些定向字符串定义了常量,您可以将其作为列表提供,例如W
或(W, E)
。
创建剩余的小部件
然后我们对其余的小部件做完全相同的事情。我们有一个标签,用于显示我们计算的结果米数。我们有一个“计算”按钮,按下它来执行计算。最后,我们有三个静态文本标签。对于这些小部件中的每一个,我们首先创建它,然后将其放置在屏幕上网格中的适当单元格中。
meters = StringVar()
ttk.Label(mainframe, textvariable=meters).grid(column=2, row=2, sticky=(W, E))
ttk.Button(mainframe, text="Calculate", command=calculate).grid(column=3, row=3, sticky=W)
ttk.Label(mainframe, text="feet").grid(column=3, row=1, sticky=W)
ttk.Label(mainframe, text="is equivalent to").grid(column=1, row=2, sticky=E)
ttk.Label(mainframe, text="meters").grid(column=3, row=2, sticky=W)
添加一些设置
然后,我们对用户界面进行了一些收尾工作。
for child in mainframe.winfo_children():
child.grid_configure(padx=5, pady=5)
feet_entry.focus()
root.bind("<Return>", calculate)
第一部分遍历内容框架中的所有小部件,并在每个小部件周围添加了一点填充,这样它们就不会那么紧缩在一起。(当我们第一次将小部件放在屏幕上时,我们可以将这些grid
选项添加到每个调用中,但循环遍历是更好的快捷方式。)
第二部分告诉 Tk 将焦点放在我们的输入小部件上。这样,光标将在该字段中开始,因此用户在开始键入之前不必单击它。
第三行告诉 Tk,如果用户按下 Enter 键,它应该调用calculate函数,就像按下计算按钮一样。
执行计算
说到这里,我们在这里定义我们的计算程序。当用户按下计算按钮或按下回车键时调用它。它执行英尺到米的计算。
def calculate(*args):
try:
value = float(feet.get())
meters.set(int(0.3048 * value * 10000.0 + 0.5)/10000.0)
except ValueError:
pass
如您所见,此例程从我们的输入小部件中获取英尺数,进行计算,并将结果放入我们的标签小部件中。
说什么?看起来我们没有对这些小部件做任何事情!这是我们在创建小部件时指定的textvariable
魔法选项发挥作用的地方。我们将全局变量feet
指定为输入框的文本变量,这意味着无论何时输入发生变化,Tk 都会自动更新全局变量feet
。类似地,如果我们显式更改与小部件关联的文本变量的值(正如我们所做的那样,meters
附加到我们的标签上),小部件将自动更新为变量的当前内容。对于 Python,唯一需要注意的是这些变量必须是StringVar
类的实例。
启动事件循环
最后,我们需要告诉 Tk 进入它的事件循环,这是所有东西都出现在屏幕上并允许用户与之交互所必需的。
root.mainloop()
还有一件事…
由于本教程强调 Tkinter,我们的示例使用独立脚本代码、全局变量和简单函数。在实践中,您可能会在函数或类中组织除最简单脚本之外的任何内容。有不同的方法可以做到这一点:使用模块、为用户界面的不同部分创建类、从 Tkinter 类继承等。
但通常,您只想做一些简单的事情来封装您的数据,而不是将所有内容都放入全局变量空间。重写英尺到米的例子,以将主要代码封装到一个类中。请注意self
(在全局范围内执行)和StringVar
的使用。
from tkinter import *
from tkinter import ttk
class FeetToMeters:
def __init__(self, root):
root.title("Feet to Meters")
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
self.feet = StringVar()
feet_entry = ttk.Entry(mainframe, width=7, textvariable=self.feet)
feet_entry.grid(column=2, row=1, sticky=(W, E))
self.meters = StringVar()
ttk.Label(mainframe, textvariable=self.meters).grid(column=2, row=2, sticky=(W, E))
ttk.Button(mainframe, text="Calculate", command=self.calculate).grid(column=3, row=3, sticky=W)
ttk.Label(mainframe, text="feet").grid(column=3, row=1, sticky=W)
ttk.Label(mainframe, text="is equivalent to").grid(column=1, row=2, sticky=E)
ttk.Label(mainframe, text="meters").grid(column=3, row=2, sticky=W)
for child in mainframe.winfo_children():
child.grid_configure(padx=5, pady=5)
feet_entry.focus()
root.bind("<Return>", self.calculate)
def calculate(self, *args):
try:
value = float(self.feet.get())
self.meters.set(int(0.3048 * value * 10000.0 + 0.5)/10000.0)
except ValueError:
pass
root = Tk()
FeetToMeters(root)
root.mainloop()