python——GUI纸上谈兵 之canvas完全攻略

Tkinter 提供了 Canvas 组件来实现绘图。程序既可在 Canvas 中绘制直线、矩形、椭圆等各种几何图形,也可绘制图片、文字、UI 组件(如 Button)等。Canvas 允许重新改变这些图形项(Tkinter 将程序绘制的所有东西统称为 item)的属性,比如改变其坐标、外观等。

Canvas 组件的用法与其他 GUI 组件一样简单,程序只要创建并添加 Canvas 组件,然后调用该组件的方法来绘制图形即可。如下程序示范了最简单的 Canvas 绘图:

from tkinter import *
# 创建窗口
root = Tk()
# 创建并添加Canvas
cv = Canvas(root, background='white')
cv.pack(fill=BOTH, expand=YES)
cv.create_rectangle(30, 30, 200, 200,
outline='red', # 边框颜色
stipple = 'question', # 填充的位图
fill="red", # 填充颜色
width=5 # 边框宽度
)
cv.create_oval(240, 30, 330, 200,
outline='yellow', # 边框颜色
fill='pink', # 填充颜色
width=4 # 边框宽度
)
root.mainloop()

上面程序先创建并添加了 Canvas 组件,分别绘制了矩形和椭圆。运行上面程序,可以看到如图 1 所示的效果。

图 1 最简单的 Canvas 绘图

从上面程序可以看到,Canvas 提供了create_rectangle()方法绘制矩形和 create_oval() 方法绘制椭圆(包括圆,圆是椭圆的特例)。实际上,Canvas 还提供了如下方法来绘制各种图形:

create_arc:绘制弧。

create_bitmap:绘制位图。

create_image:绘制图片。

create_line():绘制直线。

create_polygon:绘制多边形。

create_text:绘制文字。

create_window:绘制组件。

Canvas 的坐标系统是绘图的基础,其中点 (0,0) 位于 Canvas 组件的左上角,X 轴水平向右延伸,Y 轴垂直向下延伸。

绘制上面这些图形时需要简单的几何基础:

1.在使用 create_line()绘制直线时,需要指定两个点的坐标,分别作为直线的起点终点

2.在使用 create_rectangle() 绘制矩形时,需要指定两个点的坐标,分别作为矩形左上角点右下角点的坐标

3.在使用 create_oval()绘制椭圆时,需要指定两个点的坐标,分别作为左上角点右下角点的坐标来确定一个矩形,而该方法则负责绘制该矩形的内切椭圆(内切即椭圆的边框和矩形的边框相切)

4.在使用create_arc绘制弧时,和 create_oval的用法相似,因为弧是椭圆的一部分,因此同样也是指定左上角和右下角两个点的坐标,默认总是绘制从 3 .0开始,逆时针旋转 90°的那一段弧。程序可通过start改变起始角度,也可通过 extent改变转过的角度。

5.在使用 create_polygon绘制多边形时,需要指定多个点的坐标来作为多边形的多个定点;在使用create_bitmapcreate_imagecreate_textcreate_window 等方法时,只要指定一个坐标点,用于指定目标元素的绘制位置即可。

在绘制这些图形时可指定如下选项:

fill:指定填充颜色。如果不指定该选项,默认不填充。

outline:指定边框颜色。

width:指定边框宽度。如果不指定该选项,边框宽度默认为 1。

dash:指定边框使用虚线。该属性值既可为单独的整数,用于指定虚线中线段的长度;也可为形如(5,2,3)格式的元素,此时5 指定虚线中线段的长度,2 指定间隔长度,3 指定虚线长度……依此类推。

stipple:使用位图平铺进行填充。该选项可与 fill 选项结合使用,fill 选项用于指定位图的颜色。

style:指定绘制弧的样式。该选项仅对 create_arc 方法起作用(即绘制弧线)。该选项支持 PIESLICE(扇形)、CHORD(弓形)、ARC(仅绘制弧)选项值。

start:指定绘制弧的起始角度。该选项仅对 create_arc方法起作用。

extent:指定绘制弧的角度。该选项仅对 create_arc方法起作用。

arrow:指定绘制直线时两端是否有箭头。该选项支持NONE两端无箭头)、FIRST(开始端有箭头)、LAST(结束端有箭头)、BOTH(两端都有箭头)选项值。

arrowshape:指定箭头形状。该选项是一个形如 “20 20 10” 的字符串,字符串中的三个整数依次指定填充长度箭头长度箭头宽度

joinstyle:指定直接连接点的风格。仅对绘制直线多向形有效。该选项支持 METTERROUND(圆角)、BEVEL(斜角) 选项值。

anchor:指定绘制文字、GUI 组件的位置。该选项仅对 create_text()create_window()方法有效。

justify:指定文字的对齐方式。该选项支持 CENTER、LEFT、RIGHT 常量值,该选项仅对 create_text方法有效。

下面程序示范了通过不同的方法来绘制不同的图形,这些图形分别使用不同的边框、不同的填充效果:

from tkinter import *
# 创建窗口
root = Tk()
root.title('绘制图形项')
# 创建并添加Canvas
cv = Canvas(root, background='white', width=830, height=830)
cv.pack(fill=BOTH, expand=YES)
columnFont = ('微软雅黑', 18)
titleFont = ('微软雅黑', 20, 'bold')
# 使用循环绘制文字
for i, st in enumerate(['默认', '指定边宽', '指定填充', '边框颜色', '位图填充']):
    cv.create_text((130 + i * 140, 20),text = st,
    font = columnFont,
    fill='gray',
    anchor = W,
    justify = LEFT)
# 绘制文字
cv.create_text(10, 60, text = '绘制矩形',
font = titleFont,
fill='magenta',
anchor = W,
justify = LEFT)
# 定义列表,每个元素的4个值分别指定边框宽度、填充色、边框颜色、位图填充
options = [(None, None, None, None),
(4, None, None, None),
(4, 'pink', None, None),
(4, 'pink', 'blue', None),
(4, 'pink', 'blue', 'error')]
# 采用循环绘制5个矩形
for i, op in enumerate(options):
    cv.create_rectangle(130 + i * 140, 50, 240 + i * 140, 120,
    width = op[0], # 边框宽度
    fill = op[1], # 填充颜色
    outline = op[2], # 边框颜色
    stipple = op[3]) # 使用位图填充
# 绘制文字
cv.create_text(10, 160, text = '绘制椭圆',
font = titleFont,
fill='magenta',
anchor = W,
justify = LEFT)
# 定义列表,每个元素的4个值分别指定边框宽度、填充色、边框颜色、位图填充
options = [(None, None, None, None),
(4, None, None, None),
(4, 'pink', None, None),
(4, 'pink', 'blue', None),
(4, 'pink', 'blue', 'error')]
# 采用循环绘制5个椭圆
for i, op in enumerate(options):
	cv.create_oval(130 + i * 140, 150, 240 + i * 140, 220,
	width = op[0], # 边框宽度
	fill = op[1], # 填充颜色
	outline = op[2], # 边框颜色
stipple = op[3]) # 使用位图填充
# 绘制文字
cv.create_text(10, 260, text = '绘制多边形',
font = titleFont,
fill='magenta',
anchor = W,
justify = LEFT)
# 定义列表,每个元素的4个值分别指定边框宽度、填充色、边框颜色、位图填充
options = [(None, "", 'black', None),
(4, "", 'black', None),
(4, 'pink', 'black', None),
(4, 'pink', 'blue', None),
(4, 'pink', 'blue', 'error')]
# 采用循环绘制5个多边形
for i, op in enumerate(options):
	cv.create_polygon(130 + i * 140, 320, 185 + i * 140, 250, 240 + i * 140, 320,
	width = op[0], # 边框宽度
	fill = op[1], # 填充颜色
	outline = op[2], # 边框颜色
	stipple = op[3]) # 使用位图填充
# 绘制文字
cv.create_text(10, 360, text = '绘制扇形',
font = titleFont,
fill='magenta',
anchor = W,
justify = LEFT)
# 定义列表,每个元素的4个值分别指定边框宽度、填充色、边框颜色、位图填充
options = [(None, None, None, None),
(4, None, None, None),
(4, 'pink', None, None),
(4, 'pink', 'blue', None),
(4, 'pink', 'blue', 'error')]
# 采用循环绘制5个扇形
for i, op in enumerate(options):
	cv.create_arc(130 + i * 140, 350, 240 + i * 140, 420,
	width = op[0], # 边框宽度
	fill = op[1], # 填充颜色
	outline = op[2], # 边框颜色
	stipple = op[3]) # 使用位图填充
# 绘制文字
cv.create_text(10, 460, text = '绘制弓形',
font = titleFont,
fill='magenta',
anchor = W,
justify = LEFT)
# 定义列表,每个元素的4个值分别指定边框宽度、填充色、边框颜色、位图填充
options = [(None, None, None, None),
(4, None, None, None),
(4, 'pink', None, None),
(4, 'pink', 'blue', None),
(4, 'pink', 'blue', 'error')]
# 采用循环绘制5个弓形
for i, op in enumerate(options):
    cv.create_arc(130 + i * 140, 450, 240 + i * 140, 520,
    width = op[0], # 边框宽度
    fill = op[1], # 填充颜色
    outline = op[2], # 边框颜色
    stipple = op[3], # 使用位图填充
    start = 30, # 指定起始角度
    extent = 60, # 指定逆时针转过角度
    style = CHORD) # CHORD指定绘制弓
# 绘制文字
cv.create_text(10, 560, text = '仅绘弧',
font = titleFont,
fill='magenta',
anchor = W,
justify = LEFT)
# 定义列表,每个元素的4个值分别指定边框宽度、填充色、边框颜色、位图填充
options = [(None, None, None, None),
(4, None, None, None),
(4, 'pink', None, None),
(4, 'pink', 'blue', None),
(4, 'pink', 'blue', 'error')]
# 采用循环绘制5个弧
for i, op in enumerate(options):
	cv.create_arc(130 + i * 140, 550, 240 + i * 140, 620,
	width = op[0], # 边框宽度
	fill = op[1], # 填充颜色
	outline = op[2], # 边框颜色
	stipple = op[3], # 使用位图填充
	start = 30, # 指定起始角度
	extent = 60, # 指定逆时针转过角度
	style = ARC) # ARC指定仅绘制弧
# 绘制文字
cv.create_text(10, 660, text = '绘制直线',
font = titleFont,
fill='magenta',
anchor = W,
justify = LEFT)
# 定义列表,每个元素的5个值分别指定边框宽度、线条颜色、位图填充、箭头风格, 箭头形状
options = [(None, None, None, None, None),
(6, None, None, BOTH, (20, 40, 10)),
(6, 'pink', None, FIRST, (40, 40, 10)),
(6, 'pink', None, LAST, (60, 50, 10)),
(8, 'pink', 'error', None, None)]
# 采用循环绘制5个弧
for i, op in enumerate(options):
	cv.create_line(130 + i * 140, 650, 240 + i * 140, 720,
	width = op[0], # 边框宽度
	fill = op[1], # 填充颜色
	stipple = op[2], # 使用位图填充
	arrow = op[3], # 箭头风格
	arrowshape = op[4]) # 箭头形状
# 绘制文字
cv.create_text(10, 760, text = '绘制位图\n图片、组件',
font = titleFont,
fill='magenta',
anchor = W,
justify = LEFT)
# 定义包括create_bitmap, create_image, create_window三个方法的数组
funcs = [Canvas.create_bitmap, Canvas.create_image, Canvas.create_window]
# 为上面3个方法定义选项
items = [{'bitmap' : 'questhead'},
{'window':Button(cv,text = '单击我', padx=10, pady=5,
command = lambda :print('按钮单击')),'anchor': W}]
for i, func in enumerate(funcs):
    func(cv, 230 + i * 140, 780, **items[i])
    root.mainloop()

上面程序示范了 Canvas 中不同的 create_xxx 方法的功能和用法,它们可用于创建矩形、椭圆、多边形、扇形、弓形、弧、直线、位图、图片和组件等。在绘制不同的图形时可指定不同的选项,从而实现丰富的绘制效果。

运行上面程序,效果如下:

python——GUI纸上谈兵 之canvas完全攻略_第1张图片

Canvas操作图形项的标签

Canvas 中通过 create_xxx 方法绘制图形项之后,这些图形项井不是完全静态的图形,每个图形项都是一个独立的对象,程序完全可以动态地修改、删除这些图形项。

Canvas 以“堆叠”的形式来管理这些图形项,先绘制的图形项位于“堆叠”的下面,后绘制的图形项位于“堆叠”的上面。因此,如果两个图形项有重叠的部分,那么后绘制的图形项(位于上面)会遮挡先绘制的图形项。

为了修改、删除这些图形项,程序需要先获得这些图形项的引用。获得这些图形项的引用有两种方式:

1.通过图形项的 id,也就是 Canvas 执行 create_xxx()方法的返回值。一般来说,create_xxx() 会依次返回1、2、3 等整数作为图形项的id

2.通过图形项的 tag(标签)
在 Canvas 中调用 create_xxx() 方法绘图时,还可传入一个tags 选项,该选项可以为所绘制的图形项(比如矩形、椭圆、多边形等)添加一个或多个 tag(标签)。此外,Canvas 还允许调用方法为图形项添加 tag、删除 tag 等,这些 tag 也相当于该图形项的标识,程序完全可以根据 tag 来获取图形项。

总结来说,Canvas 提供了如下方法来为图形项添加 tag:

1.addtag_aboove(self, newtag, tagOrId):为 tagOrId 对应图形项的上一个图形项添加新 tag。

2.addtag_all(self, newtag):为所有图形项添加新 tag。

3.addtag_below(self, newtag, tagOrId):为 tagOrId 对应图形项的下一个图形项添加新 tag。

4.addtag_closest(self, newtag, x, y):为和 x、y 点最接近的图形项添加新 tag。

5.addtag_enclosed(self, newtag, x1, y1, x2, y2):为指定矩形区域内最上面的图形项添加新tag。其中 x1、y1 确定矩形区域的左上角坐标;x2、y2 确定矩形区域的右下角坐标。

6.addtag_overlapping(self, newtag, x1, y1, x2, y2):为与指定矩形区域重叠的最上面的图形项添加tag。

7.addtag_withtag(self, newtag, tagOrId):为 tagOrId 对应图形项添加新 tag。

Canvas 提供了如下方法来删除图形项的tag:

1.dtag(self, *args):删除指定图形项的tag。

Canvas 提供了如下方法来获取图形项的所有tag

gettagsself, *args):获取指定图形项的所有tag。

Canvas 提供了如下方法根据 tag 来获取其对应的所有图形项

find_withtag(self, tagOrId):获取tagOrId 对应的所有图形项。

为了更好地理解上面方法的作用,下面用一个程序来进行演示:

from tkinter import *
# 创建窗口
root = Tk()
root.title('操作标签')
# 创建并添加Canvas
cv = Canvas(root, background='white', width=620, height=250)
cv.pack(fill=BOTH, expand=YES)
# 绘制一个矩形框
rt = cv.create_rectangle(40, 40, 300, 220,
outline='blue', width=2,
tag = ('t1', 't2', 't3', 'tag4')) # 为该图形项指定标签
# 访问图形项的id,也就是编号
print(rt) # 1
# 绘制一个椭圆
oval = cv.create_oval(350, 50, 580, 200,
fill='yellow', width=0,
tag = ('g1', 'g2', 'g3', 'tag4')) # 为该图形项指定标签
# 访问图形项的id,也就是编号
print(oval) # 2
# 根据指定tag该tag对应的所有图形项
print(cv.find_withtag('tag4')) # (1, 2)
# 获取指定图形项的所有tag
print(cv.gettags(rt)) # ('t1', 't2', 't3', 'tag4')
print(cv.gettags(2)) # ('g1', 'g2', 'g3', 'tag4')
cv.dtag(1, 't1') # 删除id为1的图形项上名为t1的tag
cv.dtag(oval, 'g1') # 删除id为oval的图形项上名为g1的tag
# 获取指定图形项的所有tag
print(cv.gettags(rt)) # ('tag4', 't2', 't3')
print(cv.gettags(2)) # ('tag4', 'g2', 'g3')
# 为所有图形项添加tag
cv.addtag_all('t5')
print(cv.gettags(1)) # ('tag4', 't2', 't3', 't5')
print(cv.gettags(oval)) # ('tag4', 'g2', 'g3', 't5')
# 为指定图形项添加tag
cv.addtag_withtag('t6', 'g2')
# 获取指定图形项的所有tag
print(cv.gettags(1)) # ('tag4', 't2', 't3', 't5')
print(cv.gettags(oval)) # ('tag4', 'g2', 'g3', 't5', 't6')
# 为指定图形项上面的图形项添加tag, t2上面的就是oval图形项
cv.addtag_above('t7', 't2')
print(cv.gettags(1)) # ('tag4', 't2', 't3', 't5')
print(cv.gettags(oval)) # ('tag4', 'g2', 'g3', 't5', 't6', 't7')
# 为指定图形项下面的图形项添加tag, g2下面的就是rt图形项
cv.addtag_below('t8', 'g2')
print(cv.gettags(1)) # ('tag4', 't2', 't3', 't5', 't8')
print(cv.gettags(oval)) # ('tag4', 'g2', 'g3', 't5', 't6', 't7')
# 为最接近指定点的图形项添加tag,最接近360、90的图形项是oval
cv.addtag_closest('t9', 360, 90)
print(cv.gettags(1)) # ('tag4', 't2', 't3', 't5', 't8')
print(cv.gettags(oval)) # ('tag4', 'g2', 'g3', 't5', 't6', 't7', 't9')
# 为位于指定区域内(几乎覆盖整个图形区)的最上面的图形项添加tag
cv.addtag_closest('t10', 30, 30, 600, 240)
print(cv.gettags(1)) # ('tag4', 't2', 't3', 't5', 't8')
print(cv.gettags(oval)) # ('tag4', 'g2', 'g3', 't5', 't6', 't7', 't9', 't10')
# 为与指定区域内重合的最上面的图形项添加tag
cv.addtag_closest('t11', 250, 30, 400, 240)
print(cv.gettags(1)) # ('tag4', 't2', 't3', 't5', 't8')
print(cv.gettags(oval)) # ('tag4', 'g2', 'g3', 't5', 't6', 't7', 't9', 't10', 't11')
root.mainloop()

上面程序示范了操作图形项的 tag 的方法,而且列出了每次操作之后的输出结果。因此,读者可以结合程序的运行结果来理解 Canvas 是如何管理图形项的 tag 的。

操作图形项

在 Canvas 中获取图形项之后,接下来可通过 Canvas 提供的大量方法来操作图形项。总结起来,Canvas 提供了如下方法在图形项“堆叠”中查找图形项:

find_above(self, tagOrId):返回 tagOrId 对应图形项的上一个图形项。

find_all(self):返回全部图形项。

find_below(self, tagOrId):返回 tagOrId 对应图形项的下一个图形项。

find_closest(self, x, y):返回和 x 、y 点最接近的图形项。

find_enclosed(self, x1, y1, x2, y2):返回位于指定矩形区域内最上面的图形项。

find_overlapping(self, x1, y1, x2, y2):返回与指定矩形区域重叠的最上面的图形项。

find_withtag(self, tagOrId):返回 tagOrId 对应的全部图形项。

Canvas 提供了如下方法在图形项“堆叠”中移动图形项

tag_lower(self, *args)|lower:将args的第一个参数对应的图形项移到“堆叠”的最下面。也可额外指定一个参数,代表移动到指定图形项的下面。

tag_raise(self, *args)|lift:将args的第一个参数对应的图形项移到“堆叠”的最上面。也可额外指定一个参数,代表移动到指定图形项的上面。

如果程序希望获取或修改图形项的选项,则可通过 Canvas 的如下方法来操作:

itemcget(self, tagOrId, option):获取tagOrId 对应图形项的option 选项值。

itemconfig(self, tagOrId, cnf=None, **kw):为tagOrId 对应图形项配置选项。

itemconfigure:该方法与上一个方法完全相同。

Canvas 提供了如下方法来改变图形项的大小和位置

coords(self, *args):重设图形项的大小和位置。

move(self, *args):移动图形项,但不能改变大小。简单来说,就是在图形项的 x、y 基础上加上新的 mx、my 参数。

scale(self, *args):缩放图形项。该方法的 args 参数要传入 4 个值,其中前两个值指定缩放中心;后两个值指定 x、y 方向的缩放比。

此外,Canvas 还提供了如下方法来删除图形项或文字图形项(由 create_text 方法创建)中间的部分文字:

delete(self, *args):删除指定 id 或 tag 对应的全部图形项。

dchars(self, *args):删除文字图形项中间的部分文字。

下面程序示范了操作图形项的方法:

from tkinter import *
from tkinter import colorchooser
import threading
# 创建窗口
root = Tk()
root.title('操作图形项')
# 创建并添加Canvas
cv = Canvas(root, background='white', width=400, height=350)
cv.pack(fill=BOTH, expand=YES)
# 该变量用于保存当前选中的图形项
current = None
# 该变量用于保存当前选中的图形项的边框颜色
current_outline = None
# 该变量用于保存当前选中的图形项的边框宽度
current_width = None
# 该函数用于高亮显示选中图形项(边框颜色会red、yellow之间切换)
def show_current():
# 如果当前选中项不为None
if current is not None:
# 如果当前选中图形项的边框色为red,将它改为yellow
if cv.itemcget(current, 'outline') == 'red':
cv.itemconfig(current, width=2,
outline='yellow')
# 否则,将颜色改为red
else:
cv.itemconfig(current, width=2,
outline='red')
global t
# 通过定时器指定0.2秒之后执行show_current函数
t = threading.Timer(0.2, show_current)
t.start()
# 通过定时器指定0.2秒之后执行show_current函数
t = threading.Timer(0.2, show_current)
t.start()
# 分别创建矩形、椭圆、和圆
rect = cv.create_rectangle(30, 30, 250, 200,
fill='magenta', width='0')
oval = cv.create_oval(180, 50, 380, 180,
fill='yellow', width='0')
circle = cv.create_oval(120, 150, 300, 330,
fill='pink', width='0')
bottomF = Frame(root)
bottomF.pack(fill=X,expand=True)
liftbn = Button(bottomF, text='向上',
# 将椭圆移动到它上面的item之上
command=lambda : cv.tag_raise(oval, cv.find_above(oval)))
liftbn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
lowerbn = Button(bottomF, text='向下',
# 将椭圆移动到它下面的item之下
command=lambda : cv.tag_lower(oval, cv.find_below(oval)))
lowerbn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
def change_fill():
# 弹出颜色选择框,让用户选择颜色
fill_color = colorchooser.askcolor(parent=root,
title='选择填充颜色',
# 初始颜色设置为椭圆当前的填充色(fill选项值)
color = cv.itemcget(oval, 'fill'))
if fill_color is not None:
cv.itemconfig(oval, fill=fill_color[1])
fillbn = Button(bottomF, text='改变填充色',
# 该按钮触发change_fill函数
command=change_fill)
fillbn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
def change_outline():
# 弹出颜色选择框,让用户选择颜色
outline_color = colorchooser.askcolor(parent=root,
title='选择边框颜色',
# 初始颜色设置为椭圆当前的边框色(outline选项值)
color = cv.itemcget(oval, 'outline'))
if outline_color is not None:
cv.itemconfig(oval, outline=outline_color[1],
width=4)
outlinebn = Button(bottomF, text='改变边框色',
# 该按钮触发change_outline函数
command=change_outline)
outlinebn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
movebn = Button(bottomF, text='右下移动',
# 调用move方法移动图形项
command=lambda : cv.move(oval, 15, 10))
movebn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
coordsbn = Button(bottomF, text='位置复位',
# 调用coords方法重设图形项的大小和位置
command=lambda : cv.coords(oval, 180, 50, 380, 180))
coordsbn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
# 再次添加Frame容器
bottomF = Frame(root)
bottomF.pack(fill=X,expand=True)
zoomoutbn = Button(bottomF, text='缩小',
# 调用scale方法对图形项进行缩放
# 前面两个坐标指定缩放中心,后面两个参数指定横向、纵向的缩放比
command=lambda : cv.scale(oval, 180, 50, 0.8, 0.8))
zoomoutbn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
zoominbn = Button(bottomF, text='放大',
# 调用scale方法对图形项进行缩放
# 前面两个坐标指定缩放中心,后面两个参数指定横向、纵向的缩放比
command=lambda : cv.scale(oval, 180, 50, 1.2, 1.2))
zoominbn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
def select_handler(ct):
global current, current_outline, current_width
# 如果ct元组包含了选中项
if ct is not None and len(ct) > 0:
ct = ct[0]
# 如果current对应的图形项不为空
if current is not None:
# 恢复current对应的图形项的边框
cv.itemconfig(current, outline=current_outline,
width = current_width)
# 获取当前选中图形项的边框信息
current_outline = cv.itemcget(ct, 'outline')
current_width = cv.itemcget(ct, 'width')
# 使用current保存当前选中项
current = ct
def click_handler(event):
# 获取当前选中的图形项
ct = cv.find_closest(event.x, event.y)
# 调用select _handler处理选中图形项
select_handler(ct)
def click_select():
# 取消为“框选”绑定的两个事件处理函数
cv.unbind('')
cv.unbind('')
# 为“点选”绑定鼠标点击的事件处理函数
cv.bind('', click_handler)
clickbn = Button(bottomF, text='点选图形项',
# 该按钮触发click_select函数
command=click_select)
clickbn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
# 记录鼠标拖动的第一个点的x、y坐标
firstx = firsty = None
# 记录前一次绘制的、代表选择区的虚线框
prev_select = None
def drag_handler(event):
global firstx, firsty, prev_select
# 刚开始拖动时,用鼠标位置为firstx、firsty赋值
if firstx is None and firsty is None:
firstx, firsty = event.x, event.y
leftx, lefty = min(firstx, event.x), min(firsty, event.y)
rightx, righty = max(firstx, event.x), max(firsty, event.y)
# 删除上一次绘制的虚线选择框
if prev_select is not None:
cv.delete(prev_select)
# 重新绘制虚线选择框
prev_select = cv.create_rectangle(leftx, lefty, rightx, righty,
dash=2)
def release_handler(event):
global firstx, firsty
if prev_select is not None:
cv.delete(prev_select)
if firstx is not None and firsty is not None:
leftx, lefty = min(firstx, event.x), min(firsty, event.y)
rightx, righty = max(firstx, event.x), max(firsty, event.y)
firstx = firsty = None
# 获取当前选中的图形项
ct = cv.find_enclosed(leftx, lefty, rightx, righty)
# 调用select _handler处理选中图形项
select_handler(ct)
def rect_select():
# 取消为“点选”绑定的事件处理函数
cv.unbind('')
# 为“框选”绑定鼠标拖动、鼠标释放的事件处理函数
cv.bind('', drag_handler)
cv.bind('', release_handler)
rectbn = Button(bottomF, text='框选图形项',
# 该按钮触发rect_select函数
command=rect_select)
rectbn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
deletebn = Button(bottomF, text='删除',
# 删除图形项
command=lambda : cv.delete(oval))
deletebn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
root.mainloop()
```python

# 转载自http://www.uml.org.cn/python/201912161.asp


 
 
	

你可能感兴趣的:(Python,GUI,python,html5)