5.2.3 在画布上绘图

本节介绍如何在画布上绘制图形。为了完整起见,我们将前面介绍过的首先需要执行的

几条语句合在一起复制如下:

>>> from Tkinter import *
>>> root = Tk()
>>> c = Canvas(root,width=300,height=200,bg='white')
>>> c.pack()

如前所述,c 是一个画布对象,而画布对象提供了若干方法用于绘制矩形、椭圆、多边 形等图形。为了画特定图形,只要向画布对象 c 发出执行特定方法的请求即可。

矩形

画布对象提供 create_rectangle()方法,用于在画布上创建矩形。矩形的位置和大 小由两点定义:(x0,y0)给出矩形的左上角,(x1,y1)给出矩形的右下角①。用法如下:

create_rectangle(x0,y0,x1,y1,<选项设置>...)
id = create_rectangle(x0,y0,x1,y1,<选项设置>...)

① 准确地说,矩形并不包含(x1,y1),即(x1,y1)位于矩形右下角之外。例如,用左上角(10,10)和右下角(12,12)

定义的矩形实际上大小是 2 像素×2 像素,包含像素(11,11)但不包含像素(12,12)。

create_rectangle()的返回值是所创建的矩形的标识号,第一种用法没有保存这个 标识号,而第二种用法将标识号存入了一个变量。

例如,下面的语句创建一个以(50,50)为左上角、以(200,100)为右下角的矩形:

>>> c.create_rectangle(50,50,200,100) 1

结果如图 5.5(a)所示。注意,语句返回的 1 是矩形的标识号,表示这个矩形是画布上的 1 号

图形项。为了将来在程序中引用图形,最好用变量来保存图形的标识号,或者将图形与某个 标签相关联。例如我们再创建一个矩形:

>>> r2 = c.create_rectangle(80,70,240,150,tags="rect#2")
>>> print r2 2

结果如图 5.5(b)所示。可见,第二个矩形的标识号为 2,它还与标签"rect#2"相关联。

(a)

(b)

图 5.5 在画布上画矩形

矩形图形实际上可视为由两个部分组成:轮廓线和内部。矩形轮廓线可以用选项 outline 来设置颜色,其缺省值是黑色,即等同于设置 outline="black"。如果将 outline 设置为空串"",则不显示轮廓线(透明的轮廓线)。轮廓线的宽度可以用选项 width 来设置,缺省值为 1 像素。矩形内部可以用选项 fill 来设置填充颜色,此选项的 缺省值是空串,即等同于设置 fill="",效果是内部透明。

轮廓线可以画成虚线形式,这需要用到选项 dash,该选项的值是整数元组。最常用的 是 2 元组(a,b),其中 a 指定要画几个像素,b 指定要跳过几个像素,依此重复,直至轮廓 线画完。若 a、b 相等,可以简记为(a,)。

矩形还有个选项 state,用于设置图形的显示状态。缺省值是 NORMAL(或"normal"), 即正常显示。另一个有用的值是 HIDDEN(或"hidden"),它使矩形在画布上不可见。使 一个图形在 NORMAL 和 HIDDEN 两个状态之间交替变化,能形成闪烁的效果。

另外,5.2.2 中介绍过可以用选项 tags 为矩形关联标签,这里就不重复了。 上面例子中没有为两个矩形设置任何选项,即所有选项都取各自的缺省值。如 5.2.2 中所介绍的,我们可以利用画布对象的方法 itemconfig()来设置选项值。例如:

>>> c.itemconfig(1,fill="black")
>>> c.itemconfig(r2,fil1="grey",outline="white",width=6)

执行后的结果如图 5.6 所示。

图 5.6 修改图形选项

将图 5.5 和图 5.6 相比较即可看出,在画布上,后创建的矩形是覆盖在先创建的矩形之 上的,并且未涂色时矩形内部是透明的(能看到被覆盖的矩形的轮廓线)。事实上,画布上 的所有图形项都是按创建次序堆叠起来的,第一个创建的图形项处于画布最底部(最靠近背 景),最后创建的图形项处于画布最顶部(最靠近前景)①。图形的位置如果有重叠,则上面 的图形会遮挡下面的图形。

如上一小节所介绍的,可以使用画布对象的 delete()和 move()方法删除和移动图 形。例如下列语句删去第二个矩形(结果见图 5.7(a)),并将第一个矩形在 x 轴和 y 轴方向 都移动 50 个像素(结果见图 5.7(b)):

>>> c.delete(r2)
>>> c.move(1,50,50)

(b)

图 5.7 图形的删除和移动

至此我们详细介绍了矩形的画法、选项设置和图形操作(删除、移动等),接下去介绍 其他图形时会有很多相似的内容,以后我们将不重复详述。

顺便提一下,画布对象没有提供画“点”的方法,但我们可以画一个极小的矩形来当作 点。例如:

>>> c.create_rectangle(50,50,51,51)

① 即所有图形项形成一个显示列表。画布提供方法来对此列表重新排序。具体方法可参考 Tkinter 资料。

最后说明一下绘制矩形时如何提供坐标数据。create_rectangle()方法中坐标参数 的形式是很灵活的,既可以直接提供坐标值,也可以先将坐标数据存入变量,然后将该变量 传给该方法;既可以将所有坐标数据构成一个元组,也可以将它们组成多个元组。例如, create_rectangle()方法中的四个坐标参数既可以如上面例子那样作为四个值,也可以 定义成两个点(两个 2 元组)分别赋值给两个变量,还可以定义成一个 4 元组并赋值给一个 变量。形如:

>>> p1 = (10,10)
>>> p2 = (50,80)
>>> c.create_rectangle(p1,p2,tags="#3")
>>> xy = (100,110,200,220)
>>> c.create_rectangle(xy)

将坐标存储在变量中的做法是值得推荐的,因为这更便于在绘制多个图形时计算、安排 它们的相互位置。要强调的是,这里介绍的内容对所有图形(只要用到坐标参数)都是适用 的。

椭圆形

画布对象提供 create_oval()方法,用于在画布上画一个椭圆形(特例是圆形)。椭 圆的位置和尺寸通过其限定框(bounding box,即外接矩形)决定,而限定框由左上角坐标 (x0,y0)和右下角坐标(x1,y1)定义(参见图 5.8)。

图 5.8 用限定框定义椭圆 创建椭圆的语句模板如下:

create_oval(x0,y0,x1,y1,<选项设置>...)
id = create_oval(x0,y0,x1,y1,<选项设置>...)

create_oval()的返回值是所创建的椭圆形的标识号,第一种用法没有保存这个标识号,而第二种用法将标识号存入了一个变量。

例如,下面的语句序列描绘地球绕太阳旋转的轨道,其中分别创建了一个椭圆形和两个 圆形,并且为大圆形涂上红色表示太阳,为小圆形涂上蓝色表示地球(参见图 5.9)。

>>> o1 = c.create_oval(50,50,250,150)
>>> o2 = c.create_oval(110,85,140,115,fill='red')
>>> o3 = c.create_oval(245,95,255,105,fill='blue')

图 5.9 椭圆和圆

和矩形类似,椭圆形的常用选项包括 fill、outline、width、dash、state 和 tags等。

画布对象的 delete()方法、move()方法和 itemconfig()方法同样可用于椭圆形 的删除、移动和选项设置。

弧形

画布对象提供 create_arc()方法,用于在画布上创建一个弧形。与椭圆的绘制类似, create_arc()的参数是用来定义一个矩形的左上角和右下角的坐标,该矩形唯一确定了 一个内接椭圆形(特例是圆形),而最终要画的弧形是该椭圆的一段。创建弧形的语句模板 如下:

create_arc(x0,y0,x1,y1,<选项设置>...)
id = create_arc(x0,y0,x1,y1,<选项设置>...)

create_arc()的返回值是所创建的弧形的标识号,第一种用法没有保存这个标识号,而第二种用法将标识号存入了一个变量。

弧形的开始位置由选项 start 定义,其值为一个角度(以 x 轴方向为 0 度);弧形的结 束位置由选项 extent 定义,其值表示从开始位置逆时针旋转的角度。start 的缺省值为0 度,extent 的缺省值为 90 度。显然,如果 start 设置为 0 度,extent 设置为 360 度, 则画出一个完整的椭圆形,效果和 create_oval()方法一样。

选项 style 用于规定弧形的式样,可以取三种值:PIESLICE 或"pieslice"是扇形(弧形两端与圆心相连),ARC 或"arc"是弧(圆周上的一段),CHORD 或"chord"是弓形(弧加连接弧两端点的弦)。style 的缺省值是 PIESLICE。如图 5.10 所示。

图 5.10 三种弧形

弧形的其他常用选项 outline、fill、width、dash、state 和 tags 的意义和缺 省值都和矩形类似。注意只有 PIESLICE 和 CHORD 形状才可填充颜色。

下面的例子画了一个扇形、一条弧和一个弓形,结果如图 5.11 所示。

>>> bbox = (50,50,250,150)
>>> c.create_arc(bbox)
>>> c.create_arc(bbox,start=100,extent=140,style="arc",width=4)
>>> c.create_arc(bbox,start=250,extent=110,style="chord")

图 5.11 弧形

画布对象的 delete()方法、move()方法和 itemconfig()方法同样可用于弧形的 删除、移动和选项设置。

线条

画布对象提供 create_line()方法,用于在画布上创建连接多个点的线段序列,其语 句模板如下:

create_line(x0,y0,x1,y1,...,xn,yn,<选项设置>...)
id = create_line(x0,y0,x1,y1,...,xn,yn,<选项设置>...)

create_line()方法将各点(x0,y0)、(x1,y1)、…、(xn,yn)按顺序用线条连接起来,返回值是所创建的线条的标识号。第一种用法没有保存这个标识号,而第二种用法将标识号存入了一个变量。 没有特别说明的话,相邻两点间用直线连接,即图形整体上是条折线。但如果将选项 smooth 设置成非 0 值,则各点被解释成 B-样条曲线的顶点,图形整体是一条平滑的曲线。 不同于矩形、椭圆、弧形中的扇形和弓形的是,线条不能形成轮廓线和内部区域两部分,因此没有 outline 选项,只有 fill 选项。选项 fill 在此意为线条的颜色,其缺省值为 黑色。选项 width 设置线条宽度,缺省值为 1 像素。

线条可以通过选项 arrow 来设置箭头,该选项的缺省值是 NONE(无箭头)。如果将 arrow 设置为 FIRST 或"first",则箭头在(x0,y0)端;设置为 LAST 或"last",则箭 头在(xn,yn)端;设置为 BOTH 或"both",则两端都有箭头。

选项 arrowshape 用于描述箭头形状,其值为 3 元组(d1,d2,d3),含义如图 5.12 所 示。缺省值为(8,10,3)。

图 5.12 箭头形状的定义

线条和前面介绍的各种图形一样,具有 dash、state、tags 等选项。

下面的语句序列画的是北斗七星(大熊座)和北极星:其中 s1 到 s7 以及 polaris

给出了各星的坐标,我们在这些位置创建了涂黑的圆形表示北斗七星和北极星,然后用直线 段依次连接 s1 到 s7,另外沿 s6-s7 延长线方向画了根带箭头的虚线指向北极星①。最下 方曲线表示地球表面,这里虽然只提供了三个点,但 Tkinter 仍能画出一条相当平滑的曲线。

>>> s1 = (20,20)
>>> s2 = (60,40)
>>> s3 = (80,60)
>>> s4 = (85,80)
>>> s5 = (70,100)
>>> s6 = (85,115)
>>> s7 = (110,100)
>>> polaris = (220,40)
>>> c.create_oval(s1,(23,23),fill='black')
>>> c.create_oval(s2,(63,43),fill='black')
>>> c.create_oval(s3,(83,63),fill='black')
>>> c.create_oval(s4,(88,83),fill='black')
>>> c.create_oval(s5,(73,103),fill='black')
>>> c.create_oval(s6,(88,118),fill='black')
>>> c.create_oval(s7,(113,103),fill='black')
>>> c.create_oval((222,36),(226,42),fill='black')
>>> c.create_line(s1,s2,s3,s4,s5,s6,s7,s4)
>>> c.create_line(s7,polaris,dash=(4,),arrow=LAST)
>>> c.create_line(5,190,150,160,295,190,smooth=1)

结果如图 5.13 所示。

图 5.13 线条

画布对象的 delete()方法、move()方法和 itemconfig()方法同样可用于线条的 删除、移动和选项设置。

多边形

画布对象提供 create_polygon()方法,用于在画布上创建一个多边形。与线条类似, 多边形是用一系列顶点(至少三个)的坐标定义的,系统将把这些顶点按次序连接起来。与 线条不同的是,最后一个顶点需要与第一个顶点连接,从而形成封闭的形状。

① 这是利用北斗七星寻找北极星进行定向的常识方法。

创建多边形的语句模板如下:

create_polygon(x0,y0,x1,y1, ..., <选项设置>...)
id = create_polygon(x0,y0,x1,y1, ..., <选项设置>...)

create_polygon()的返回值是所创建多边形的标识号,第一种用法没有保存这个标识号,而第二种用法将标识号存入了一个变量。

和矩形类似,outline 和 fill 分别设置多边形的轮廓线颜色和内部填充色;但与矩 形不同的是,多边形的 outline 选项缺省值为空串,即轮廓线不可见,而 fill 选项的缺 省值为黑色。

与线条类似,一般用直线连接顶点,但如果将选项 smooth 设置成非 0 值,则表示用B-样条曲线连接顶点,这样绘制的是由平滑曲线围成的图形。

下面的语句序列以不同方式连接 5 个点,或设置不同的选项值,形成三种不同的五边形:

>>> p11,p21,p31 = (70,20),(70+100,20),(70,20+100)
>>> p12,p22,p32 = (35,50),(35+100,50),(35,50+100)
>>> p13,p23,p33 = (55,85),(55+100,85),(55,85+100)
>>> p14,p24,p34 = (85,85),(85+100,85),(85,85+100)
>>> p15,p25,p35 = (105,50),(105+100,50),(105,50+100)
>>> c.create_polygon(p11,p12,p13,p14,p15)
>>> c.create_polygon(p21,p23,p25,p22,p24,outline="black",fill="")
>>> c.create_polygon(p31,p32,p33,p34,p35,outline="black",fill="")

执行结果如图 5.14 所示。

图 5.14 多边形

多边形的另几个常用选项 width、dash、state 和 tags 的用法都和矩形类似。 画布对象的 delete()方法、move()方法和 itemconfig()方法同样可用于多边形的删除、移动和选项设置。

文本

画布对象提供 create_text()方法,用于在画布上显示一行或多行文本。这里,文本 是作为图形对象看待的,与普通的字符串不同。创建文本的语句模板如下:

create_text(x,y,<选项设置>...)
id = create_text(x,y,<选项设置>...)

其中(x,y)指定显示文本的参考位置。create_text()的返回值是所创建的文本的标识 号,第一种用法没有保存这个标识号,而第二种用法将标识号存入了一个变量。

文本内容由选项 text 设置,其值就是显示的字符串。字符串中可以使用换行字符"\n", 从而实现多行文本的显示。

选项 anchor 用于指定文本的哪个“锚点”与显示位置(x,y)对齐。首先想象文本有 个界限框,Tkinter 为界限框定义了若干个“锚点”,锚点用东南西北等方位常量表示,如图 5.15 所示。通过锚点可以控制文本的相对位置,例如,若将 anchor 设置为 SW,则将文本界限框的左下角置于参考点(x,y);若将 anchor 设置为 N,则将文本界限框的顶边中点置 于参考点(x,y)。anchor 的缺省值为 CENTER,表示将文本的中心置于参考点(x,y)。

图 5.15 锚点

选项 fill 用于设置文本的颜色,缺省值为黑色。如果设置为空串,则文本不可见。 选项 justify 用于控制多行文本的对齐方式,其值为 LEFT、CENTER 或 RIGHT,缺省值为 LEFT。而 width 用于控制文本的宽度,超出宽度就要换行。 选项 state、tags 的意义同前。 下面的语句序列演示了如何在画布上安排文本:

>>> t1 = c.create_text(10,10,text="NW@(10,10)",anchor=NW)
>>> c.create_text(150,10,text="N@(150,10)",anchor=N)
>>> c.create_text(290,10,text="NE@(290,10)",anchor=NE)
>>> c.create_text(10,100,text="W@(10,100)",anchor=W)
>>> c.create_text(150,100,text="CENTER@(150,100)\n2nd Line")
>>> c.create_text(290,100,text="E@(290,100)",anchor=E)
>>> c.create_text(10,190,text="SW@(10,190)",anchor=SW)
>>> c.create_text(150,190,text="S@(150,190)",anchor=S)
>>> c.create_text(290,190,text="SE@(290,190)",anchor=SE)

结果如图 5.16 所示。

图 5.16 文本

程序中可能需要读取或修改文本的内容,画布对象的 itemcget()和 itemconfig()方法可用于此目的。例如:

>>> print c.itemcget(t1,"text")
NW@(10,10)
>>> c.itemconfig(t1,text="NorthWest")

其中第一行读取标识号为 t1 的文本项的 text 选项值;第三行将标识号为 t1 的文本的 text 选项重新设置为"NorthWest"。

画布对象的 delete()方法、move()方法同样可用于文本的删除和移动。

图像

除了在画布上自己画图,还可以将来自文件的现成图像显示在画布上。Tkinter 针对不 同格式的图像文件有不同的显示方法,这里我们只介绍显示 gif 格式图像的方法。

第一步是利用 Tkinter 提供的 PhotoImage 类来创建图像对象,语句模板如下:

img = PhotoImage(file = <图像文件名>)

其中选项 file 用于指定图像文件(支持 gif、pgm、ppm 格式①),PhotoImage()返回值是一个图像对象,这里我们用变量 img 引用这个对象,接下去将把这个图像对象显示在画布中②。

第二步是在画布上显示图像,这可通过画布对象提供的 create_image()方法完成。 该方法的用法如下:

c.create_image(x,y,image = <图像对象>,<选项设置>...)
id = c.create_image(x,y,image=<图像对象>,<选项设置>...)

其中(x,y)是决定图像显示位置的参考点;image 选项决定显示的图像,其值就是第一步创建的图像对象。create_image()的返回值是所创建的图像在画布上的标识号,第一种用法没有保存这个标识号,而第二种用法将标识号存入了一个变量。

图像在画布上的位置由参考点(x,y)和 anchor 选项决定,具体设置与文本相同。 例如,假设电脑上有个文件 C:\WINDOWS\Web\exclam.gif ,则下列语句序列首先为该图像文件创建了一个图像对象 pic,然后将该图像对象显示在了画布中:

>>> pic = PhotoImage(file = "C:\WINDOWS\Web\exclam.gif")
>>> c.create_image(150,100,image=pic)

结果如图 5.17 所示。

图 5.17 画布上显示图像 可以为图像设置选项 state、tags,意义同前。

画布对象的 delete()方法、move()方法同样可用于图像的删除和移动。

① 至于常见的 jpg 格式或其他格式的图像,可以利用 Python 图像库(PIL)转换成 Tkinter 图像对象。

② 还可以显示在按钮(Button)、标签(Label)、文本(Text)等 GUI 构件中,参见第 8 章。

除了以上各种图形、文字和图像,我们还可以在画布上放置其他 GUI 构件,例如按钮、 勾选钮等,以便用户更好地与画布进行交互。读者学习了第 8 章后可以试着编写这样的程序。