斌哥教你自制千分秒表(键盘控制)
共 4748字,需浏览 10分钟
·
2021-02-08 19:32
上节课我们绘制了用鼠标控制的千分秒表,还指出了一个隐藏的bug及其解决方案。今天我们来绘制使用键盘控制的千分秒表,请大家比较它与上节课代码的区别。
话不多说,上代码。
素材准备:
项目目标:
1. 绘制秒表显示框;
2. 实现用空格键控制“开始/暂停”功能;
3. 实现用回车键控制“清除”功能。
项目实施过程:
一、主函数代码说明。
1. 创建画笔和屏幕:
import turtle as tt
import time
tt.TurtleScreen._RUNNING = True # 启动绘图,在IDE中运行加这句可避免报错
time_pen, text_pen = tt.Pen(), tt.Pen()
tt.hideturtle() #隐藏画笔
time_pen.hideturtle() #隐藏画笔
text_pen.hideturtle() #隐藏画笔
game = tt.Screen()
screen_w, screen_h = 600, 400
game.setup(screen_w, screen_h)
tt.tracer(0)
注释:主画笔tt用来绘制方框等不需擦除的图形,分别使用time_pen和text_pen来绘制时间和提示信息。
2. 绘制各功能键和秒表显示框:
#w, h, (x0, y0)分别存储了图片单位格子(像素)宽、高和左上角坐标
w, h, x0, y0 = 30, 40, -200, 150
draw_info(x0+w*5.5, y0+h*0.3, "按空格交替开始和暂停,按回车归零", 20, "black", tt)
draw_square(x0+w*3, y0, w*5, h, "black",tt)
draw_info(x0+w*5.5, y0-h*5/6, "00:00:00", 18, "red", time_pen)
3. 定义全局变量:
num = 0 #用来统计暂停次数,以便输出每次计时信息
total_times = 0 #用来统计前几轮计时总时长
pass_time = 0 #用来统计本轮计时时长
start_flag = False #标记秒表是否处于计时状态,False表示处于停止状态
clear_flag = False #标记是否按下了“清除”按钮,False表示没有按下
start_time = time.perf_counter() #设置计时起始时间为当前时间
4. 设置键盘触发函数,并监听屏幕,以便接收键盘事件:
tt.onkeypress(enter, "Return")
tt.onkeypress(space, "space")
tt.listen() # 监听
5. 死循环,让秒表开始工作,并随时响应按键事件,同时需要刷新每一帧画面:
while True:
if not start_flag: #秒表处于停止状态
start_time = time.perf_counter() #设置计时起始时间为当前时间
else: #秒表处于计时状态
pass_time = time.perf_counter() - start_time #计算本轮计时时长
hour = (total_times + pass_time) // 3600
minute = ((total_times + pass_time) - hour * 3600) // 60
second = (total_times + pass_time) % 60
show_time = f'{hour:02.0f}:{minute:02.0f}:{second:.3f}'
time_pen.clear()
draw_info(x0+w*5.5, y0-h*5/6, show_time, 18, "red", time_pen)
if clear_flag: #点击“清除”按钮
time_pen.clear()
draw_info(x0+w*5.5, y0-h*5/6, "00:00:00", 18, "red", time_pen)
tt.update() #刷新每一帧画面
tt.done()
注释:若秒表处于停止状态,则时刻更新起始时间start_time为当前时间,否则保持起始时间不变,根据当前时间计算本轮计时时长,并将计时时长显示到方框中。刷新每一帧画面,用新时间取代旧时间。
二、绘制各功能键和显示文本
1. 根据输入的坐标,使用指定画笔显示文本信息:
'''
函数功能:根据输入的坐标,显示文本信息
函数名:draw_info(x, y, text, size, color, mypen)
参数表:x, y -- 文本信息位置;
text -- 文本信息内容;
size, color -- 文本信息字体和颜色;
mypen -- 当前画笔对象。
返回值:没有返回值。
'''
def draw_info(x, y, text, size, color, mypen):
mypen.penup()
mypen.goto(x, y)
mypen.pendown()
mypen.color(color)
mypen.write(text, align="center", font=("黑体", size, "normal"))
2. 根据输入的坐标,使用指定画笔绘制方框:
'''
函数功能:根据输入的坐标和大小,绘制方框并填充颜色
函数名:draw_square(x, y, w, h, color, mypen)
参数表:x, y -- 方框左上角坐标;
w, h -- 方框的宽和高;
color -- 填充方框的颜色;
mypen -- 绘制方框所需要的画笔
返回值:没有返回值。
'''
def draw_square(x, y, w, h, color, mypen):
mypen.penup()
mypen.goto(x, y)
mypen.down()
mypen.seth(0)
mypen.fillcolor(color)
mypen.begin_fill()
for i in range(2):
mypen.fd(w)
mypen.right(90)
mypen.fd(h)
mypen.right(90)
mypen.end_fill()
三、根据按下的键盘名称,执行相应操作
1. 函数说明:
为了响应键盘按下事件,需要为每个按键设置无参函数。
其中按下回车键相当于用鼠标点击“清除”按钮,需要把所有数据都归零,并重新绘制时间显示屏内容。
按下空格键相当于用鼠标点击“开始/暂停”按钮。若秒表处于计时状态,则将秒表状态改成暂停,同时将本轮计时时长pass_time加入到总时长total_times中,然后在秒表下方显示本轮计时时长;若秒表处于暂停状态,则将秒表状态改成计时。
2. 自定义函数解析:
'''
函数功能:键盘响应按下回车键,清除所有文字显示信息,并修改相应全局变量,准备重新计时。
函数名:enter()
参数表:没有参数,在调用函数时,指定了按下的键名称。
返回值:没有返回值。
'''
def enter():
global start_flag, clear_flag, total_times, num
start_flag, clear_flag = False, True
total_times, num = 0, 0
text_pen.clear()
'''
函数功能:键盘响应按下空格键,交替实现“开始”和“暂停”功能,并修改相应全局变量。
函数名:space()
参数表:没有参数,在调用函数时,指定了按下的键名称。
返回值:没有返回值。
'''
def space():
global start_flag, clear_flag, total_times, num
if start_flag: #秒表处于计时状态
total_times += pass_time
num += 1
hour = pass_time // 3600
minute = (pass_time - hour * 3600) // 60
second = pass_time % 60
show_time = f'第{num}轮:{hour:02.0f}:{minute:02.0f}:{second:.3f}'
draw_info(x0+w*5.5, y0-h*(1+num*0.8), show_time, 16, "black", text_pen)
start_flag, clear_flag = not start_flag, False
四、课后思考
1. 鼠标响应事件和键盘响应事件有什么区别?为什么键盘响应事件中需要加tt.listen()语句,而鼠标响应事件却不需要?
2. 在上节课中,我们把监控鼠标响应事件的game.onclick(play_game)语句放在了tt.update()语句后面;这节课中我们把监控键盘响应事件的tt.listen()语句放在了while循环语句前面,这样做效果一样吗?能否把game.onclick(play_game)语句也放在while循环语句前面?
结语:
需要本文word版的,可以加入“Python算法之旅”知识星球参与讨论和下载文件,“Python算法之旅”知识星球汇集了数量众多的同好,更多有趣的话题在这里讨论,更多有用的资料在这里分享。
我们专注Python算法,感兴趣就一起来!
相关优秀文章: