Skip to content

Canvas 组件

虽然我们能用 Tkinter 设计不少东西了,但是还没法随心所欲地去绘制我们想要的界面。

Canvas 组件,是一个可以让你任性的组件,一个可以让你随心所欲地绘制界面的组件。Canvas 是一个通用的组件,它通常用于显示和编辑图形。可以用它来绘制直线、圆形、多边形,甚至是绘制其他组件。

在 Canvas 组件上绘制对象,可以用 create_xxx() 的方法(xxx 表示对象类型,例如直线 line、矩形 rectangle 和文本 text 等):

绘制线条

python
import tkinter as tk

root = tk.Tk()
root.geometry('500x300')
w = tk.Canvas(root)
w.pack(fill=tk.BOTH, expand=True)
#  画一条黄色的横线 (0,150), (500, 150)
w.create_line(0, 150, 500, 150, fill="yellow")
#  画一条红色的竖线(虚线) (250, 0), (250, 300)
w.create_line(250, 0, 250, 300, fill="red", dash=(4, 4))
root.mainloop()

image-20210221151442265

注意,添加到 Canvas上的对象会一直保留着。如果你希望修改它们,你可以使用 coords()、itemconfig() 和 move() 方法来移动画布上的对象,或者使用 delete() 方法来删除:

python
import tkinter as tk

root = tk.Tk()
root.geometry('500x300')
w = tk.Canvas(root)
w.pack(fill=tk.BOTH, expand=True)

line1 = w.create_line(0, 150, 500, 150, fill="yellow")
line2 = w.create_line(250, 0, 250, 300, fill="red", dash=(4, 4))

# 创建一个矩形
rect1 = w.create_rectangle(100, 75, 300, 225, fill="blue")

# 修改线条的位置
w.coords(line1, 0, 75, 200, 75)

# 填充矩形的颜色
w.itemconfig(rect1, fill="red")

# 删除一条线
w.delete(line2)

tk.Button(root, text="删除全部", command=(lambda x=tk.ALL: w.delete(x))).pack()
root.mainloop()

绘制矩形

image-20210221152116135

还可以在 Canvas上显示文本,使用的是 create_text() 方法:

python
import tkinter as tk

root = tk.Tk()
w = tk.Canvas(root, width=200, height=100)
w.pack()

w.create_line(0, 0, 200, 100, fill="green", width=3)
w.create_line(200, 0, 0, 100, fill="green", width=3)
w.create_rectangle(40, 20, 160, 80, fill="green")
w.create_rectangle(65, 35, 135, 65, fill="yellow")
w.create_text(100, 50, text="hello")

tk.Button(root, text="删除全部", command=(lambda x=tk.ALL: w.delete(x))).pack()

root.mainloop()

image-20210221152858834

使用 create_oval() 方法绘制椭圆形(或圆形),参数是指定一个限定矩形(Tkinter 会自动在这个矩形内绘制一个椭圆)

而绘制圆形就是把限定矩形设置为正方形即可:

python
import tkinter as tk

width = 500
height = 300
root = tk.Tk()
root.geometry('{}x{}'.format(width, height))
w = tk.Canvas(root)
w.pack(fill=tk.BOTH, expand=True)

w.create_rectangle(width * 0.2, height * 0.2, width * 0.8, height * 0.8, dash=(4, 4), fill="green")
w.create_oval(width * 0.2, height * 0.2, width * 0.8, height * 0.8, fill="pink")
w.create_text(width * 0.5, height * 0.5, text="hello")

tk.Button(root, text="删除全部", command=(lambda x=tk.ALL: w.delete(x))).pack()

root.mainloop()

image-20210221153149033

绘制多边形

如果想要绘制多边形,可以使用 create_polygon() 方法。好,现在带大家来画一个五角星。首先,要先确定五个角的坐标。那么高中数学不是体育老师教的鱼油们应该看得懂这张图(看不懂也没关系哈,知道结果就行,因为现在的目标是用 Tkinter 画五角星,而不是学三角函数)

python
import tkinter as tk
import math

width = 500
height = 300
root = tk.Tk()
root.geometry('{}x{}'.format(width, height))
w = tk.Canvas(root)
w.pack(fill=tk.BOTH, expand=True)

center_x = width / 2
center_y = height / 2
r = 100

points = [
    # 左上点
    center_x - int(r * math.sin(2 * math.pi / 5)),
    center_y - int(r * math.cos(2 * math.pi / 5)),
    # 右上点
    center_x + int(r * math.sin(2 * math.pi / 5)),
    center_y - int(r * math.cos(2 * math.pi / 5)),
    # 左下点
    center_x - int(r * math.sin(math.pi / 5)),
    center_y + int(r * math.cos(math.pi / 5)),
    # 顶点
    center_x,
    center_y - r,
    # 右下点
    center_x + int(r * math.sin(math.pi / 5)),
    center_y + int(r * math.cos(math.pi / 5))
]
w.create_polygon(points, outline='green', fill='yellow')

root.mainloop()

image-20210221153356868

绘制画板

接着设计一个像 Windows 画图工具那样的面板,让用户可以在上面随心所欲地绘画。

其实实现原理也很简单,就是获取用户拖动鼠标的坐标,然后每个坐标对应绘制一个点上去就可以了。在这里,不得不承认有点遗憾让人的是Tkinter并没有提供画“点”的方法。

但是程序是死的,程序员是活的!可以通过绘制一个超小的椭圆形来表示一个“点”。在下面的例子中,通过响应“鼠标左键按住拖动”事件(<B1-Motion>),在鼠标拖动的同时获取鼠标的实时位置(x,y),并绘制一个超小的椭圆来代表一个“点”:

python
import tkinter as tk
import math

root = tk.Tk()

w = tk.Canvas(root, width=200, height=100, background='#ffffff')
w.pack()


def paint(event):
    x1, y1 = (event.x - 1), (event.y - 1)
    x2, y2 = (event.x + 1), (event.y + 1)
    w.create_oval(x1, y1, x2, y2, fill='blue')


w.bind('<B1-Motion>', paint)

tk.Label(root, text='按住鼠标并移动,开始绘制理想的蓝图').pack()
root.mainloop()

image-20210221153549429

总结

关于画布对象还有些概念,我们觉得必须了解,这里给大家做个总结:

arc(弧形、弦或扇形)。

bitmap(内建的位图文件或XBM格式的文件)。

image(BitmapImage或PhotoImage的实例对象)。

line(线)。

oval(圆或椭圆形)。

polygon(多边形)。

rectangle(矩形)。

text(文本)。

window(组件)。

其中,弦、扇形、椭圆形、圆形、多边形和矩形这些“封闭式”图形都是由轮廓线和填充颜色组成的,通过 outline 和 fill 选项设置它们的颜色,还可以设置为透明(传入空字符串表示透明)。

坐标系

由于画布可能比窗口大(带有滚动条的 Canvas 组件),因此 Canvas 组件可以选择使用两种坐标系:

窗口坐标系——以窗口的左上角作为坐标原点。

画布坐标系——以画布的左上角作为坐标原点。

画布对象显示的顺序

Canvas 组件中创建的画布对象都会被列入显示列表中,越接近背景的画布对象位于显示列表的越下方。显示列表决定当两个画布对象重叠的时候是如何覆盖的(默认情况下新创建的会覆盖旧的画布对象的重叠部分,即位于显示列表上方的画布对象将覆盖下方那个)。当然,显示列表中的画布对象可以被重新排序。