tkinter01:安装及第一个窗口


原文: https://tkdocs.com/tutorial/firstexample.html

在 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()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蔚蓝慕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值