5.2.2 创建画布
为了绘图,首先要有画布。Tkinter 中提供了画布(Canvas),可以在画布上绘制图形、 文本,也可以在上面放置命令按钮等 GUI 构件。画布实际上是一个 Canvas 对象,它包含 一些属性(如画布的高度、宽度、背景色等),也包含一些方法(如在画布上创建图形、删 除或移动图形等)。
创建画布对象的语句模板如下:
c = Canvas(<窗口>,<选项 1>=<值 1>,<选项 2>=<值 2>,...)
其中 Canvas 是 Tkinter 提供的类(class),所谓“类”其实就和 int、float 等一样是数据类型,只不过不是 Python 语言的内建类型,而是 Tkinter 模块带来的扩展类型。Canvas就像一个制造画布的工厂,每次执行 Canvas()都能制造出一个画布对象。参数<窗口>表示画布所在的窗口,诸<选项>=<值>为画布对象的选项(即属性)进行赋值。总之,整条语句创建一个 Canvas 对象,对该对象的数据进行设置,并将该对象赋值给变量 c(更准确的 说法是变量 c 引用该对象)。
画布的常用选项包括 height(画布高度)、width(画布宽度)和 bg(或 background, 画布背景色)等,需要在创建画布对象时进行设置。创建画布对象时如果不设置这些选项的 值,则各选项取各自的缺省值,例如 bg 的缺省值为浅灰色。画布对象的所有选项都可以在 创建以后的任何时候重新设置。
下面的语句在根窗口 root 中创建一个宽度为 300 像素①、高度为 200 像素、背景为白 色的画布:
>>> c = Canvas(root,width=300,height=200,bg='white')
注意,虽然至此已经创建了画布对象,但在根窗口中并没有看到这块白色画布,这就好 比从商店买来了画布,但还没有铺到桌子上一样。为了让画布在窗口中显现出来,还需要执 行如下“布置画布”的语句②:
>>> c.pack()
现在,我们在屏幕上看到原来的根窗口(背景色为浅灰色)中放进了一个 300x200 的白色画 布。如图 5.3 所示。
图 5.3 放入画布后的根窗口
这里需要对 c.pack()所用到的“点表示法”加以说明。过去,当我们编写了一个函数f()来操作数据 x,传统的表示法是 f(x)。而在面向对象编程中,数据和操作被结合在一 起形成了对象,如果要对对象中的数据执行操作,通常采用点表示法——“对象.操作”。在 c.pack()中,变量 c 表示一个 Canvas 对象,pack()是 Canvas 对象能够响应的一个方 法,故 c.pack()就表示向对象 c 发出执行 pack()方法的请求。
① 像素(pixel)是能显示的最小图像单元,通俗说就是一个点。数字图像是由很多点组成的。
② 在窗口中布置各种构件需要使用布局管理器,这里的 pack()就是一种布局管理器。详见第 8 章。
坐标系
创建了画布,接下来就可以在画布上绘制各种图形了。为了在绘图时指定图形的绘制位 置,Tkinter 为画布建立了坐标系统。画布坐标系以画布左上角为原点,从原点水平向右为 x 轴,从原点垂直向下为 y 轴(图 5.4)。
图 5.4 画布的坐标系统
坐标如果以整数给出,则度量单位是像素,例如左上角原点的坐标为(0,0),300x200的画布的右下角坐标为(299,199)。像素是最基本、最常用的长度单位,但 Tkinter 也支持以字符串形式给出其他度量单位的长度值,例如"5c"(5 厘米)、"50m"(50 毫米)、"2i"(2 英寸)等。
图形项的标识
一个画布上可能创建多个图形项①,因此需要有办法来标识、引用其中某个图形项,以 便对该图形项进行处理。画布上的图形项有两种标识方式:
标识号:创建图形项时 Tkinter 自动为图形项赋予一个唯一的整数编号。
标签:图形项可以与字符串型的标签(tag)相关联,每个图形项可以与 0、1 乃至 多个标签相关联,而同一个标签可以与多个图形项相关联。
标签相当于为图形项命名,只不过一个图形项可以有多个名字,而且不同图形项可以有 相同的名字。为图形项指定标签的方法有三种:一是在创建图形时利用选项 tags 来指定, 可以为 tags 选项提供单个字符串(单个名字),也可以提供一个字符串元组(多个名字); 二是在图形创建之后,任何时候都可以利用画布的 itemconfig()方法来设置;三是利用 画布的 addtag_withtag()方法来为图形项增添新标签。假设我们已经创建了画布 c,则 可以执行:
>>> r1 = c.create_rectangle(20,20,100,80,tags="#1")
>>> r2 = c.create_rectangle(40,50,200,180,tags=("myRect","#2"))
>>> c.itemconfig(r1,tags=("myRect","rectOne"))
>>> c.addtag_withtag("ourRect","rectOne")
① 每个图形项可以理解成一个图形对象(有自己的属性和操作),不过 Tkinter 没有采用为每种图形提供单 独的类来创建图形对象的实现方式。5.4.2 中介绍的 graphics 库则采用了更符合面向对象概念的实现。
其中第一行的含义是在画布 c 上创建了一个矩形(稍后详述),create_rectangle()返 回的标识号被赋值给变量 r1,同时将该矩形与标签"#1"相关联。同样地,第二行创建了另 一个矩形,该矩形的标识号被赋值给变量 r2,该矩形还与两个标签"myRect"和"#2"相关 联。第三行的含义是将第一个矩形的标签重新设置为"myRect"和"rectOne"(注意原标签"#1"即告失效),这里使用了标识号 r1 来引用第一个矩形。第四行的含义是为具有标签 "rectOne"的图形项(即第一个矩形)添加一个新标签"ourRect",这里使用了标签来引 用第一个矩形。至此,第一个矩形与 3 个标签"myRect"、"rectOne"和"ourRect"相关 联,其中任何一个都可用于引用该图形。注意,标签"myRect"同时引用两个矩形。
Canvas 还预定义了 ALL(或"all")标签,此标签与画布上的所有图形项相关联。
画布对象的方法
上面例子中介绍了画布对象的 itemconfig()和 addtag_withtag()方法,除此之 外,画布对象还提供很多方法用于对画布上的图形项进行各种各样的操作。将图形项的标识 号或标签作为参数传递给画布对象的方法,即可指定被操作的图形项。下面再介绍几个画布 对象的常用方法。
gettags()方法可用于获取与给定图形项相关联的所有标签。例如下面的语句显示标 识号为 r1 的图形项的所有关联标签:
>>> print c.gettags(r1) ('myRect', 'rectOne', 'ourRect')
find_withtag()方法可用于获取与给定标签相关联的所有图形项。例如下面的语句显示与"myRect"标签相关联的所有图形项,返回结果为各图形项的标识号所构成的元组:
>>> print c.find_withtag("myRect") (1,2)
delete()方法用于从画布上删除指定的图形项。例如下面的语句从画布上删除第一个矩形:
>>> c.delete(r1)
move()方法用于在画布上移动指定图形。例如,为了将第二个矩形在 x 方向移动 10像素,在 y 方向移动 20 像素,可以执行下列语句:
>>> c.move(r2,10,20)
读者可查阅 Tkinter 资料以了解更多的画布对象方法。