上节课我们绘制了用鼠标控制的千分秒表,还指出了一个隐藏的bug及其解决方案。今天我们来绘制使用键盘控制的千分秒表,请大家比较它与上节课代码的区别。
话不多说,上代码。
素材准备:
不需要任何素材,只需直接引用Python内置模块turtle和time即可。项目目标:
利用time.perf_counter()记录程序运行时间,使用海龟绘图画出时间信息,从而实现秒表计时功能:1. 绘制秒表显示框;
2. 实现用空格键控制“开始/暂停”功能;
3. 实现用回车键控制“清除”功能。
项目实施过程:
一、主函数代码说明。
1. 创建画笔和屏幕:
import turtle as ttimport timett.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, 400game.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, 150draw_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循环语句前面?
结语:
好了,到这里,就把“在线秒表”各个模块的功能和代码实现都给大家做了详细的分析了。鼠标响应和键盘响应是海龟绘图的基本操作,有必要熟练掌握。 感兴趣的老师可以分析一下“课后思考”中的问题,写出相关代码。需要改进版代码的老师可以给我留言或微信联系我。 因为本项目的数据结构和算法原理都是自己闭门造车弄出来的,难免存在不足之处,欢迎各位老师批评指正。当然,如果你是新手,需要完整的代码,那可以加入“Python算法之旅”知识星球,下载完整的源代码。需要本文word版的,可以加入“Python算法之旅”知识星球参与讨论和下载文件,“Python算法之旅”知识星球汇集了数量众多的同好,更多有趣的话题在这里讨论,更多有用的资料在这里分享。
我们专注Python算法,感兴趣就一起来!
相关优秀文章:
阅读代码和写更好的代码
最有效的学习方式