有趣的Python笔记Ⅱ_Turtle

Turtle

绘图

窗口布局

空间坐标体系

角度坐标体系


有一只海龟,在窗口正中心,可以在幕布上游走;

只要小海龟在幕布上爬行,就会有痕迹;

基础:调用库

1
2
import turtle
# 调用turtle绘图库

窗口

计量单位为像素。

通过左上角窗口开始坐标,以及窗口长宽,定位窗口。

1
2
3
4
turtle.setup(width, height, startx, starty)
# 窗口初始化,startx & starty可选,默认正中央。
turtle.title(str)
# 设置窗口标题

实例:


幕布

首先需要通过screen = turtle.getscreen()获取到海龟屏幕TurtleScreen的对象并赋值给变量screen,下文中screen均表示该海龟屏幕TurtleScreen的对象。

1
2
3
4
5
6
screen.bgcolor(*args)
# 设置或返回海龟屏幕TurtleScreen的背景色
'''
Parameters:
args – 一个颜色字符串或3个范围是0-colormode的数字或三个元组
'''
1
2
3
4
5
6
7
8
9
screen.bgpic(picname=None)
# 设置/删除背景图片或返回当前的背景图片名
'''
Parameters:
picname – 一个gif的字符串名字或"nopic"字符串或None
git图片名:表示设置海龟屏幕TurtleScreen的背景图像
"nopic":表示删除海龟屏幕TurtleScreen的背景图像
None:表示返回海龟屏幕TurtleScreen的背景图像的名称
'''
1
2
3
4
5
6
7
8
screen.screensize(canvwidth=None, canvheight=None, bg=None)
# 如果没给出参数,则返回当前的画布大小(canvaswidth, canvasheight);否则表示调整画布大小
'''
Parameters:
canvwidth – 画布宽度(正整数,单位为像素)
canvheight – 画布高度(正整数,单位为像素)
bg – 新的背景颜色(colorstring或颜色组)
'''
1
2
3
4
5
6
7
8
9
10
screen.setworldcoordinates(llx, lly, urx, ury)
# 设置用户自定义的坐标系统,如果必要的话需要切换到“world”模式,如果“world”模式已经是活动的,则会根据新的坐标重绘图纸。
# 注意:在用户自定义的坐标系统中,角度可能会出现扭曲
'''
Parameters:
llx – 画布左下角x坐标(number型)
lly – 画布左下角y坐标(number型)
urx – 画布右上角x坐标(number型)
ury – 画布右上角y坐标(number型)
'''

坐标

graph TD A[坐标体系] -->B(空间) A[坐标体系] -->C(角度) B -->|One| D[绝对坐标体系] B -->|Two| E[相对坐标体系] C -->|One| D[绝对坐标体系] C -->|Two| E[相对坐标体系]

绝对坐标体系:屏幕

相对坐标体系:小海龟(头部)

1
2
turtle.Turtle()
# 返回海龟对象
1
2
turtle.home()
# 恢复初始坐标

空间绝对坐标:

1
2
3
4
5
turtle.goto(x, y)
# 直线爬行到绝对坐标系某坐标
turtle.setpos(x, y=None)
# 同goto(),x参数可为坐标或x坐标。((1,2), None) or (1,2)
# 同setposition()
1
2
3
turtle.setx(d)
turtle.sety(d)
# 分别只更改x,y坐标

空间相对坐标:

1
2
3
4
5
6
turtle.fd(d) # forward,海龟朝前方前进d
turtle.bk(d) # back/backward,海龟朝后方后退d
turtle.circle(radius, extent=None, steps=None)
# circle,海龟从左侧开始转圈,半径为r,转过角度为angle。
# radius:为正则逆时针,为负则顺时针。(笛卡尔坐标系的角度方向)
# steps:指定半径radius下,完成extent的角度时,分了几步。(画正多边形)

角度绝对坐标:

’Standard‘模式,0 - east,逆时针(笛卡尔坐标系的角度方向)

‘logo’模式,0 - north,顺时针(时钟方向)

1
turtle.seth(angle) # set heading,设置海龟朝向方向

角度相对坐标:

1
2
turtle.left(angle) # 左/lt,设置海龟向左转向的角度
turtle.right(angle) # 右/rt,设置海龟向右转向的角度

绘图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
turtle.hideturtle()
# 隐藏海龟图标
turtle.showturtle()
# 显示海龟图标
turtle.shape(name=None)
# 设置光标外观
'''
Parameters:
name – 形状名,必须在TurtleScreen的形状字典中,如:
(粗大箭头1)“arrow”,
(海龟箭头) “turtle”,
(实心圆箭头)“circle”,
(实心方形箭头)“square”,
(粗大箭头2)“triangle”,
(默认的箭头)“classic”
'''
# 设置或返回(海龟)画笔箭头形状名


设置:

1
2
3
4
5
6
7
8
turtle.pensize()
# 设置画笔粗细,同turtle.width()
turtle.pencolor()
# 设置画笔颜色
turtle.fillcolor()
# 设置填充颜色
turtle.color(pencolor, fillcolor)
# 设置画笔颜色和填充颜色
1
2
3
4
5
6
7
8
9
10
turtle.speed()
# 设置画笔速度
# speed为0-10的整数(1-10越来越快,0表示最快)
# 无参数则返回当前速度
'''内置的速度字符串:
“fastest”: 0
“fast”: 10
“normal”: 6
“slow”: 3
“slowest”: 1'''

画笔运动:

1
2
3
turtle.penup()
turtle.pendown()
# 拿起/放下画笔
1
2
3
4
5
6
7
8
9
turtle.write(arg, move=False, align="left", font=("Arial", 8, "normal"))
# 绘制文字
'''
Parameters:
arg – object to be written to the TurtleScreen 待绘制的文本
move – True/False 设置是否绘制
align – one of the strings “left”, “center” or right”设置文本下方初始位置
font – a triple (fontname, fontsize, fonttype) 设置字体
'''

操作:

1
2
3
turtle.begin_fill()
turtle.end_fill()
# 开始/结束填充颜色
1
2
3
4
turtle.reset()
screen.reset()
# 清屏并将画笔位置和方向恢复到初始状态,保持画笔形状不变
# screen其实是TurtleScreen对象的实例,使用screen时要先通过screen = turtle.getscreen()得到
1
2
3
4
5
6
7
turtle.undo()
# 撤销最后一个动作
while turtle.undobufferentries():
turtle.undo()
# 撤销所有动作
turtle.undobufferentries()
# 返回当前可撤销次数

事件:

按下:

1
2
3
4
5
6
7
8
turtle.onclick(fun, btn=1, add=None)
# 画布上鼠标左键在当前海龟箭头位置按下时绑定一个函数;如果函数为None,则移除存在的绑定
'''
Parameters:
fun – 一个有两个参数x,y的函数,画布上鼠标左键在当前海龟箭头位置按下时将点击的坐标作为参数,调用该方法
num – 鼠标按钮的数目,默认为1(鼠标左键)
add – True或False.如果是True,将添加一个新的绑定;否则将替换前绑定
'''

弹起:

1
2
3
4
5
6
7
8
turtle.onrelease(fun, btn=1, add=None)
# 画布上鼠标左键在当前海龟箭头位置弹起时绑定一个函数;如果函数为None,则移除存在的绑定
'''
Parameters:
fun – 一个有两个参数x,y的函数,画布上鼠标左键在当前海龟箭头位置弹起时将点击的坐标作为参数,调用该方法
num – 鼠标按钮的数目,默认为1(鼠标左键)
add – True或False.如果是True,将添加一个新的绑定;否则将替换前绑定
'''

按下&拖动:

1
2
3
4
5
6
7
8
turtle.ondrag(fun, btn=1, add=None)
# 画布上鼠标左键在当前海龟箭头位置按下并拖动时绑定一个函数;如果函数为None,则移除存在的绑定
'''
Parameters:
fun – 一个有两个参数x,y的函数,画布上鼠标左键在当前海龟箭头位置按下并拖动时将点击的坐标作为参数,调用该方法
num – 鼠标按钮的数目,默认为1(鼠标左键)
add – True或False.如果是True,将添加一个新的绑定;否则将替换前绑定
'''

返回当前状态:

1
2
3
4
5
6
7
8
turtle.position()
turtle.pos()
# 返回当前坐标
turtle.xcor()
turtle.ycor()
# 分别返回x, y坐标值
turtle.distance(x, y=None)
# 返回当前坐标与坐标(x,y)间距离或当前(海龟)箭头坐标与另一个(海龟)箭头坐标间距离
1
2
turtle.filling()
# 返回填充状态(填充状态则返回True,否则返回False)
1
2
turtle.isvisible()
# 返回(海龟)画笔当前是否是可见状态,可见返回True,否则返回False
1
2
3
4
5
6
turtle.degrees(fullcircle)
# 设置一个完整圆的“量度”
# 默认值为360度,如果是360度时的90度,假如改成整圆为400量度,则此时量度应该是90/360*400
turtle.radians()
# 弧度制
# 将一个完整圆的“量度”设置成2π,如果是360度时的90度,则此时量度应该是90/360*(2π)

【Turtle Demo】:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
"""
改编自turtle.py自带demo
执行 python -m turtledemo 命令查看系统内置demo的源码

注意:1.全文中的 turtle.xxx()中的turtle本质是该海龟屏幕上默认的海龟实例对象,他等价于turtle.getturtle()返回的对象实例.即任何turtle.xxx()函数都可以写成turtle.getturtle.xxx()
2.屏幕正中心为(0,0)点
"""
import turtle
import time


def demo1():
# 恢复默认位置和默认方向
turtle.reset()
# 保留当前海龟箭头图标(此时就是普通箭头)
turtle.tracer(True)
# 画笔抬起
turtle.pu()
# 画笔向后100像素
turtle.bk(100)
# 画笔放下
turtle.pd()
# 设置画笔线条粗细为3,同turtle.width(3)
turtle.pensize(3)
# 绘制3个正方形; 填充最后一个(i 从 0 - 2循环3次)
for i in range(3):
print("当前i=", i)

if i == 2:
# < 最后一个正方形开始填充 >
turtle.begin_fill()

# 写字标识当前在画第几个正方形
turtle.write(i + 1, False, align="right")

# 画正方形
draw_square(turtle.getturtle())

if i == 2:
# 绘制完正方形后将pencolor和fillcolor设置成褐红色
turtle.color("maroon")
# < 最后一个正方形结束填充 >
turtle.end_fill()

# 每次画完正方形画笔抬起,然后向前移动30像素再放下
turtle.pu()
turtle.fd(30)
turtle.pd()

# 设置画笔线条粗细为1,同turtle.width(1)
turtle.pensize(1)
# 将pencolor和fillcolor设置成黑色
turtle.color("black")

# move out of the way
turtle.tracer(False)
# 画笔抬起
turtle.pu()
# 右转90度此时方向向下
turtle.rt(90)
# 向前(即向下)移动100像素
turtle.fd(100)
# 右转90度此时方向向左
turtle.rt(90)
# 向前(即向左)移动100像素
turtle.fd(100)
# 右转180度此时方向向右
turtle.rt(180)
# 画笔放下
turtle.pd()
# 绘制一些文本
turtle.write("画楼梯", True)
turtle.write("start", True)
# 将pencolor和fillcolor设置成红色
turtle.color("red")
# 画5个楼梯(从0-4遍历),最后heading()为0.0表示方向向右
for i in range(5):
turtle.fd(20)
turtle.lt(90)
turtle.fd(20)
turtle.rt(90)
turtle.tracer(True)
# 绘制5个填充的楼梯
turtle.begin_fill()
for i in range(5):
turtle.fd(20)
turtle.lt(90)
turtle.fd(20)
turtle.rt(90)
# 完成填充,因为此时的fillcolor为red红色,所以以红色进行填充
turtle.end_fill()
# more text


def switchpen(_turtle):
"""
间断效果
:param _turtle: 将被处理的turtle对象
"""
if _turtle.isdown():
_turtle.pu()
else:
_turtle.pd()


def draw_square(_turtle):
"""
画边长20像素的正方形
:param _turtle: 将被处理的turtle对象
"""
# 方法1
"""
old = _turtle.heading()
_turtle.setheading(315)
_turtle.circle(15, None, 4)
_turtle.setheading(old)
"""
# 方法2
for _ in range(4):
_turtle.fd(20)
_turtle.lt(90)


def demo2():
"""Demo of some new features."""
# 使用最慢速度 0最快,1-10逐渐加快
turtle.speed(1)
# 隐藏画笔(即海龟箭头),同 turtle.hideturtle()。此时只要画笔是按下状态,虽然隐藏了但是还是能绘制图形的
#turtle.ht()
# 显示画笔,同 turtle.showturtle()
#turtle.st()
# 设置画笔线条粗细为3,同turtle.width(3)
turtle.pensize(3)
# 设置海龟箭头当前方向角度(当前模式下海龟箭头当前位置指向(0,0)点的向量角度),turtle.towards(0, 0)其实是当前方向的反方向
turtle.setheading(turtle.towards(0, 0))
# 计算半径(海龟箭头当前位置到(0,0)位置距离的一半)
radius = turtle.distance(0, 0)/2.0
# 海龟箭头右转90度,即以海龟箭头当前位置到(0,0)为直径画
turtle.rt(90)
# 画18次角度为10度的小段圆弧,画笔每按下画一小段就再抬起移动一小段
for _ in range(18):
switchpen(turtle.getturtle())
turtle.circle(radius, 10)
turtle.write("wait a moment...")

# 等待2秒
time.sleep(2)

# 撤销所有
while turtle.undobufferentries():
turtle.undo()
# 清屏并将画笔位置和方向恢复到初始状态并保持画笔形状不变,即位置到原点(0, 0),因为模式是"standard"方向恢复向右,"standard"/"world"模式方向也恢复到默认的向右,"logo"模式方向恢复到默认的向上
turtle.reset()
# 海龟箭头左转90度
turtle.lt(90)
turtle.colormode(255)
# 定义等边三角形默认的边长
laenge = 10
turtle.pencolor("green")
# 设置画笔线条粗细为3, 同turtle.width(3)
turtle.pensize(3)
# 海龟箭头左转180度
turtle.lt(180)
# i为-2 到15 共遍历18次,之所以i有负数,是因为内循环中turtle.fillcolor(255-15*i, 0, 15*i)中的15*i不能超过255(即colormode的值)
for i in range(-2, 16):
print("当前i=", i)
# 后15次画的图形进行填充,每次填充色不同
if i > 0:
turtle.begin_fill()
turtle.fillcolor(255-15*i, 0, 15*i)
# 画等边三角形
for _ in range(3):
turtle.fd(laenge)
turtle.lt(120)
# 后15次画的图形填充完毕
if i > 0:
turtle.end_fill()

# 每画完一个等边三角形,等边三角形的变成增加10像素,并且角度左转15度
laenge += 10
turtle.lt(15)

# 达到 慢->快->慢->快 的效果 (速度值>10 则被置为0即最快速度)
turtle.speed((turtle.speed()+1) % 12)

# 海龟箭头左转120度
turtle.lt(120)
# 画笔抬起
turtle.pu()
# 向前移动70像素
turtle.fd(70)
# 海龟箭头向右转30度
turtle.rt(30)
# 画笔放下
turtle.pd()
# pencolor设置成红色并且fillcolor设置成黄色
turtle.color("red", "yellow")
# 速度设置成最快
turtle.speed(0)
# 画图形并填充
turtle.begin_fill()
for _ in range(4):
# 绘制1/4圆
turtle.circle(50, 90)
# 右转90度
turtle.rt(90)
# 前移30像素
turtle.fd(30)
# 右转90度
turtle.rt(90)
# 图形填充完毕
turtle.end_fill()
# 海龟箭头左转90度
turtle.lt(90)
# 画笔抬起
turtle.pu()
# 向前移动30像素
turtle.fd(30)
# 画笔放下
turtle.pd()
# 海龟箭头图标设置成海龟
turtle.shape("turtle")
# 获取(默认的)第一个Turtle实例对象
tri = turtle.getturtle() # 下文中的 tri(默认的)第一个Turtle实例对象,可以将所有的tri替换成turtle,比如tri.lt(100) 可改成 turtle.lt(100)
# 设置tri的(海龟箭头和)画笔大小的缩放模式为auto,此模式下(海龟箭头和)画笔随 pensize变化而变化.
tri.resizemode("auto")
# 创建一个新的Turtle实例对象并返回该对象实例
turtle1 = turtle.Turtle()
# 设置turtle1的(海龟箭头和)画笔大小的缩放模式为auto,此模式下(海龟箭头和)画笔随 pensize变化而变化.
turtle1.resizemode("auto")
# turtle1的海龟箭头图标设置成海龟
turtle1.shape("turtle")
turtle1.reset()
turtle1.lt(90)
# turtle1设置画笔速度为0最大速度
turtle1.speed(0)
# turtle1的画笔抬起
turtle1.pu()
# turtle1的画笔移动到坐标点(280, 40)
turtle1.goto(280, 40)
# turtle1的左转30度
turtle1.lt(30)
# turtle1的画笔放下
turtle1.pd()
# turtle1设置画笔速度为6
turtle1.speed(6)
# turtle1的pencolor设置成蓝色并且fillcolor设置成橘黄色
turtle1.color("blue", "orange")
# 设置画笔线条粗细为2, 同turtle.width(2)
turtle1.pensize(2)
# tri设置画笔速度为6
tri.speed(6)
# tri方向指向turtle1当前位置
tri.setheading(tri.towards(turtle1))
count = 1
# 只要tri与turtle1之间距离>4像素进入循环
while tri.distance(turtle1) > 4:
turtle1.fd(3.5)
turtle1.lt(0.6)
tri.setheading(tri.towards(turtle1))
tri.fd(4)
if count % 20 == 0:
# 当前位置拷贝一份turtle1实例的当前海龟箭头图标
turtle1.stamp()
# 当前位置拷贝一份tri实例的当前海龟箭头图标
tri.stamp()
# tri间断效果
switchpen(tri)
# turtle1间断效果
#switchpen(turtle1)
count += 1
tri.write("CAUGHT! ", font=("Arial", 16, "bold"), align="right")
tri.pencolor("black")
tri.pencolor("red")

# 等待2秒
time.sleep(2)

# 此处的turtle.undobufferentries()等价于turtle.getturtle().undobufferentries()或tri.undobufferentries()表示只要第一个turtle实例可以撤销,就一直撤销,因为tri的操作数量相对于turtle1要多,为了两个对象都撤销完所以用了前者
while turtle.undobufferentries():
# tri对象撤销一步
tri.undo()
# turtle1对象撤销一步
turtle1.undo()
# tri对象向前移动50像素
tri.fd(50)
tri.write(" Click anywhere to exit!", font=("Courier", 12, "bold"))
# 获取海龟屏幕TurtleScreen对象实例
screen = turtle.getscreen()
# 注册点击事件,点击海龟屏幕TurtleScreen任何位置,触发close_window函数
screen.onclick(close_window)


def close_window(x, y):
print("点击位置(", x, ",", y, ")")
# 获取当前海龟屏幕TurtleScreen的对象实例
screen = turtle.getscreen()
# 清屏
screen.clearscreen()
# 关闭窗口
screen.bye()


def my_main():
demo1()
demo2()
# 保持屏幕,直到点击窗口右上角关闭按钮或调用turtle.bye()方法
turtle.mainloop()


if __name__ == '__main__':
my_main()

【TurtleDemo2】:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
"""
执行 python -m turtledemo 命令查看系统内置demo的源码

改编自python提供的turtle_yinyang.py

"""
import turtle

# 定义大圆半径200,则小圆半径big_radius * 0.5, 假如内部最小圆半径为big_radius*0.15
big_radius = 200


def main():
turtle.reset()
turtle.shape("turtle")
yin("black", "white", 1)
yin("white", "black", -1)
turtle.ht()


def yin(big_fillcolor, inner_fillcolor, direction):
"""
画一半阴阳鱼
:param big_fillcolor: 外部大圆填充色
:param inner_fillcolor: 内部小圆填充色
:param direction: 1表示开始默认开始方向向右,-1表示开始默认开始方向向左
:return:
"""
turtle.pensize(3)
# 设置pencolor和fillcolor
turtle.color("black", big_fillcolor)
# < 开始填充 >
turtle.begin_fill()
# 画内半圆
turtle.circle(big_radius / 2.0, 180)
# 画外半圆
turtle.circle(big_radius, 180)
# 海龟箭头左转180度
turtle.lt(180)
# 反方向画内半圆,反方向画圆,半径前要加 -
turtle.circle(-big_radius / 2.0, 180)
# < 结束填充 >
turtle.end_fill()
# 画笔抬起
turtle.pu()
# 从画笔当前x位置开始画圆,因此需要减去内圆半径,y方向移动,x方向不变
turtle.sety(direction * big_radius * (0.5 - 0.15))
# 画笔放下
turtle.pd()
# 设置pencolor和fillcolor
turtle.color(big_fillcolor, inner_fillcolor)
# 开始填充内圆
turtle.begin_fill()
# 画内圆
turtle.circle(big_radius * 0.15)
# 结束填充内圆
turtle.end_fill()
# 画笔抬起
turtle.pu()
# 海龟箭头回到(0, 0)坐标
turtle.goto(0, 0)
# 画笔放下
turtle.pd()
# 海龟箭头左转180度
turtle.lt(180)
return "Done!"


if __name__ == '__main__':
main()
turtle.mainloop()

参考&拓展:

https://www.cnblogs.com/bravestarrhu/p/8287261.html