Tkinter教程3——一个例子(真实的)程序

不管常规方法如何,我们先尝试一个轻巧并且很实用的小例子。它会让你体会到在Tk程序背后看起来的最初感觉。

设计
我们要是用的例子是一个简单的GUI工具,用来将一个单位为英尺的数字转换为与其相等的米制单位数字。如果我们将其简单的描绘出来,应该看起来如下:
Tkinter教程3——一个例子(真实的)程序_第1张图片
 看起来我们需要一个短小的文本输入部件,可以让我们输入一个英尺单位的数字,同时还有一个‘Calculate’按钮,用它获取输入的英尺数字,执行计算,然后把计算后的米制数字结果放在位于输入文本框下面的位置。当然,我们还需要三个静态的标签(”Feet “,“is equivalent to”和"Meters")帮助我们指出如何使用界面。
 下面是创建该程序的Python代码:

from tkinter import *
from tkinter import ttk

def calculate(*args):
    try:
        value = float(feet.get())
        meters.set((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))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)

feet = StringVar()
meters = StringVar()

feet_entry = ttk.Entry(mainframe, width=7, textvariable=feet)
feet_entry.grid(column=2, row=1, sticky=(W, E))

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('', calculate)

root.mainloop()

最终的用户界面:

代码风格上的提示:
每一种语言,包括这部教程里的,都有多种可供选择编写风格与习惯约定,帮助我们决定如何使用变量和函数命名,过程、函数化或面向对象风格等等。
由于这本教程关注的是Tk,在这里将尽可能简单,一般会使用非常直接的代码风格,而不是专注于我们的代码在过程、模块、对象、类等方面。可能多的是,你将会看到在很多例子里会有相同的对象名、变量名等。

逐步解说
from tkinter import *
from tkinter import ttk
这两行告诉Python我们的程序需要两个模块。第一个,'tkinter',是一个绑定Tk的标准模块,当它被加载时就会让你的系统中存在的Tk库被载入。第二个,“ttk”,是Python与Tk8.5版本中新增部件的绑定。(按钮,文本框之类的都叫做部件)
提示:需要注意的是,我们已经从tkinter模块中导入了全部,所以我们能调用tkinter函数,而不需要前缀,前缀是标准调用方式。尽管如此,由于我们只导入了ttk本身,也就是说我们需要在调用ttk内部函数的时候添加前缀。比如,调用‘Entry(...)’函数,将引用tkinter模块你的函数,而只有用'ttk.Entry(...)'才能引用ttk模块内函数。正如你将要看到的,有些函数在这两个模块里都被定义了,并且有些时候你可能两者都需要。依据内容的不同,在这里使用ttk调用设备,并且在教程中使用该风格。
更新:如果你正在从老版本代码迁移到新版本代码,你会发现一件事情,就是Tkinter模块的名字都变为小写了。例如,“tkinter”而不再是"Tkinter",这是从Python3.0开始改变的。

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))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)
    仅供参考:是的,“Calculate”函数出现在之前。我们将在后面进行描述,但是程序里在靠近开始的时候要包括它,因为其他程序需要引用。
以上几行代码建立了主窗口,给定名称为“Feet to Meters”。紧接着,创建了一个框架部件,用来控制我们用户界面上所有控件,并把它们放在主窗口上。“columnconfigure”/“rowconfigure”仅仅是告诉Tk,如果主窗口改变大小,框架应该扩展到其余空间。
仅供参考:严格的说,我们可以将界面其他部分直接放如主窗口中,而不需要框架的干预。尽管如此,主窗口其本身并非是“方案”部件的一部分,所以它的背景色并不能与我们将要放入其中的方案部件相匹配,使用一个“方案”框架部件来控制内容,保证背景色的正确。

feet = StringVar()
meters = StringVar()
feet_entry = ttk.Entry(mainframe, width=7, textvariable=feet)
feet_entry.grid(column=2, row=1, sticky=(W, E))
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)
以上代码创建了我们程序的主要三个控件:一个用于输入英尺数字的输入框,一个放置米制结果数字的label标签,以及一个执行计算从操作的按钮。
对于这三个控件的每一个来说,我们需要做两件事情:创建控件本身,和将它们放入界面中。我们创建的内容窗口是作为Tk方案部件类的实例,这三个控件是这个实例的“孩子”,(这里应该翻译为子类)。在创建它们的同时,我们给定它们确定的选项。例如,输入框的宽度,按钮上的文本等等。输入框和标签都被拾取为一个神奇的“textvariable(文本变量)”,一会儿我们将看到是怎么做的。
如果这些控件被创建,它们不会自动显示在界面上,因为Tk不知道相对于其他控件,你想把它们如何放置。这就是“grid”部分做的事情。记住我们应用程序的布局网格,我们放置控件在不同的列(1,2或者3)和行(1、2和3)。“sticky”选项说明了通过使用罗盘是方位,控件将要如何在网格单元里排放,例如“w”(west)意思是定位控件到单元格的左边,“we”(west-east)意思是定位控件从左边到右边(相当于控件从左到右占满)等等。

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('', calculate)
上面三行代码让我们的界面看起来更友好。
第一行,检查框架内的所有子控件,并且在每个控件周围添加一小点距离,所以它们看起来没那么拥挤。当我们第一次放置控件到界面上时,我们可以添加这些选项到每一个"grid"调用,但这仅仅是一种漂亮的快捷方式。
第二行,告诉Tk把注意力转移到我们的输入框上,也就是说,在开始的时候,光标会默认在输入框区域内,所以用户在输入的时候,不需要先单击它。
第三行,告诉Tk如果用户按下了回车键,就会调用计算程序段,作用和点击计算按钮时一样。

def calculate(*args):
    try:
        value = float(feet.get())
        meters.set((0.3048 * value * 10000.0 + 0.5)/10000.0)
    except ValueError:
        pass
这里我们定义计算程序,当用户点击计算按钮或者按下回车键的时候会被调用。它执行从英尺到米的换算,从输入框中获取输入的英尺数字,并把结果放在标签控件中。
说什么?它看起来不像是我们用这些控件做了什么事。这就是我们在创建控件时定义的神奇的“textvariable”选项起的作用。我们为输入框定义了全局变量“feet”作为textvariable,也就是说,无论什么时候输入发生改变,Tk将自动更新全局变量“feet”。同理,如果我们明确改变一个与控件相关的textvariable的值(就像我们对链接到标签控件的“Meters”所做的那样),该控件将自动被当前变量的内容更新。很灵活。

root.mainloop()
这最后一行告诉Tk让它的事件循环,这样才能让所有的事情运行。

忘记了什么?
这里还有一些值得检查而我们没有在Tk程序中包括的。例如:
·我们没有考虑当事件改变时重绘界面
·我们没有考虑评价发送事件消息,捕获监测,或者在每个空间上处理事件
·在创建控件的时候,我们没有提供更多的选项;默认看起来已经关注了很多事情,并且我们仅仅改变了按钮上的显示文本。
·我们没有写复杂的代码来获取和设定简单控件的值,我们仅仅把它们链接到变量
·我们没有考虑当用户关闭窗口或者改变窗口大小后会发生什么
·我们没有写额外的代码让它能够跨平台工作

你可能感兴趣的:(Python综合)