看完这篇博文你一定会大有收获。在这个细分的Python领域,本人已经走在了全国最前沿。这是用turtle模块制作的多媒体案例。本人制作的东西太多,今天发一个大招。本篇摘自本人撰写的《哪咤学python进阶篇》之选学案例三:白桦林的故事.py。

有一首著名的歌叫《白桦林》,讲的是一个凄美的爱情故事。以下我们先来欣赏一下歌词,如下所示:

静静的村庄飘着白的雪

阴霾的天空下鸽子飞翔

白桦树刻着那两个名字

他们发誓相爱用尽这一生

有一天战火烧到了家乡

小伙子拿起枪奔赴边疆

心上人你不要为我担心

等着我回来在那片白桦林

天空依然阴霾依然有鸽子在飞翔

谁来证明那些没有墓碑的爱情和生命

雪依然在下那村庄依然安详

年轻的人们消失在白桦林

噩耗声传来在那个午后

心上人战死在远方沙场

她默默来到那片白桦林

望眼欲穿地每天守在那里

长长的路呀就要到尽头

那姑娘已经是白发苍苍

她时常听他在枕边呼唤

来吧亲爱的,来这片白桦林

天空依然阴霾依然有鸽子在飞翔

谁来证明那些没有墓碑的爱情和生命

雪依然在下那村庄依然安详

年轻的人们消失在白桦林

在死的时候她喃喃地说

我来了,等着我在那片白桦林

本案例是把这首歌播放出来,并且同时显示歌词。为了渲染气氛,加了一个阴天般的图片和粒子效果。粒子效果用的是很多小白点从屏幕随机往下移动。每个粒子都继承自海龟类。它们的形状都是dot,不过dot并不是海龟画图自带的形状。由于用circle形状也无法缩到最小的形状,所以作者自定义了一个最小的形状。它的顶点坐标为((0,0),(0,0))。 这个作品最关键的是在唱歌的时候歌词要同步显示。 所以就有了歌词文件的概念。它记录了每句歌词应该在哪个时间显示。以下是歌词文件里的两行。

[00:26.92]静静的村庄飘着白的雪

[00:33.27]阴霾的天空下鸽子飞翔

在上面的中括号里冒号前面的是分钟,后面是秒。在点号后面是毫秒的10倍值。我们可以利用time模块获取时间,当到达了某个时间点就显示那句歌词。这是完全可以的,显示歌词用一只海龟对象的write方法即可。不过在本作品中并没有采用上述所说的方法。为了配合ontimer命令的用法。我们把歌词文件的内容进行转换,主要是把中括号中的时间转换成了歌词应该显示多长时间,当然,并没有保存到磁盘,它只是在内存里。这是由musicwithlrc模块里make_septime_lrc函数完成的。它返回septime_lrc这个列表。这个列表的每一项是一个二元组。它如下图右边文字所示:

右边的10000, '白桦林'这句歌词就表示'白桦林'这三个字要显示10秒。算法是很简单的,只是把左图中第二行的时间减去上一行的时间。具体表现在make_septime_lrc函数中的这一句:sep = next_time - current_time。

以下是musicwithlrc模块的内容:

"""musicwithlrc.py。本程序定义两个函数,返回唱词的毫秒间隔时间和歌词。"""__author__ = "李兴球"
__date__ = "2019/2/20"def convert_to_msecond(line):"""把lrc歌词文件中里中括号里的唱点时间转换成毫秒值,即把'[00:05.25]歌词'这样的转换成(650,歌词),以元组形式返回。"""sentence = line.split("]")[-1]            # 歌词    time = line.split("]")[0]                 # 中括号里的时间     time = time[1:]                           # 下面把00:10.00这样的转换成毫秒items = time.split(".")items = [item.strip() for item in items]  # 剥皮处理      ps = int(items[-1]) * 10                  # 毫秒 time = items[0]                           # 01:33形式的时间se = int(time.split(":")[-1]) * 1000      # 秒转换成毫秒mi = int(time.split(":")[0]) * 60 * 1000  # 分转换成毫秒return (mi + se + ps,sentence)def make_septime_lrc(lrcfile):"""生成歌词的间隔时间表,给海龟画图的ontimer用,返回列表,列表中的项目是二元组。二元组的内容是歌词显示的时间和歌词。    """septime_lrc = []                        # 存放每行应该显示的时间和歌词fc = []                                 # 存放每一行f = open(lrcfile,encoding='utf-8')for line in f:line = line.strip()if len(line)>10:fc.append(line)f.close()    amounts = len(fc)# 第一行的内容,它的歌词显示时间为第二行的时间减去它的时间current_items = convert_to_msecond(fc[0])# 唱到当前行的时间和歌词for index in range(amounts-1):           # 最后一行不需要显示时间   next_line = fc[index+1]              # 下一行文件内容            next_items = convert_to_msecond(next_line) # 唱到下一行的时间和歌词current_time = current_items[0]      # 唱到此行的毫秒数next_time = next_items[0]            # 唱到下一行的毫秒数sep = next_time - current_time       # 当前行应该显示的毫秒数septime_lrc.append((sep,current_items[1].strip()))current_items = next_items return septime_lrcif __name__ == "__main__":lrc_for_ontimer = make_septime_lrc("白桦林.lrc")for lrc in lrc_for_ontimer:print(lrc)

上面的函数通过from musicwithlrc import * 被导入到白桦林的故事.py程序文件中。 在主程序中定义了名为sing的函数。它的参数为wav音乐文件名和歌词文件名。由它来播放音乐和同步显示歌词。同步显示歌词是在sing函数内再定义一个名为display_lrc的无参函数,由它调用屏幕的ontimer功能循环显示歌词。

在播放音乐的时候还要同步模拟下雪效果。这是通过首先定义一个叫Snow的类,然后由它实例化一些对象,具体由这些白色的小小粒子不断地从上到下移动而实现的。经过前面的学习,相信读者能读懂Snow类。

本案例新的知识是关于tkinter的。turtle模块是用tkinter开发的。在turtle.py里定义了_Root类。它继承自Tk类。当海龟画图启动的时候就是由它来实例化一个窗口的。以下是turtle.py中_Root类的源代码(中文注释为本书作者所加):

class _Root(TK.Tk):"""Root class for Screen based on Tkinter."""def __init__(self):TK.Tk.__init__(self)             # 生成窗口def setupcanvas(self, width, height, cwidth, cheight):self._canvas = ScrolledCanvas(self, width, height, cwidth, cheight)                                          # 新建滚动画布对象self._canvas.pack(expand=1, fill="both")  # 放置画布def _getcanvas(self):return self._canvasdef set_geometry(self, width, height, startx, starty):self.geometry("%dx%d%+d%+d"%(width, height, startx, starty))def ondestroy(self, destroy):"""使用协议机制来定义关闭窗口时触发的事件"""self.wm_protocol("WM_DELETE_WINDOW", destroy) # 关闭窗口事件def win_width(self):return self.winfo_screenwidth()def win_height(self):return self.winfo_screenheight()

在turtle.py中有_Screen类,它有一个属性叫_root。而这个_root就是根窗口。所以在海龟画图中用screen._root就能直接访问窗口对象。下面是白桦林的故事.py的源代码,相信读者经过上面的阅读配合注释就能看懂代码。

"""白桦林的故事.py,本程序新建Snow类生成粒子效果做为雪花飘落。
名为sing的函数生成一只海龟,用来在屏幕上显示歌词并播放音乐。"""__author__ = "李兴球"
__date__   = "2019/2/20"from turtle import Turtle,Screen
from random import randint,choice
from musicwithlrc import *
from winsound import PlaySound,SND_ASYNC
from tkinter import messageboxdef sing(filename,srcfilename):"""播放音乐并显示歌词"""ziti = ("楷体",22,"normal")                 # 字体样式 time_and_lrc = make_septime_lrc(srcfilename)# 时间和歌词lrc_amounts = len(time_and_lrc)             # 歌词数量 writer = Turtle(visible=False)              # 此作者是海龟writer.penup()                              # 抬笔writer.sety(30)                             # 设定y坐标writer.color("blue")                        # 字的颜色PlaySound(filename,SND_ASYNC)               # 播放音乐 lrc_index = 0                               # 歌词索引从0开始def display_lrc():                          # 定义显示歌词函数"""从列表获取歌词显示出来"""nonlocal lrc_index                      # 非本地变量if lrc_index < lrc_amounts:             # 索引小于数量则显示歌词septime,lrc = time_and_lrc[lrc_index]writer.clear()                      # 写新歌词前先擦掉writer.write(lrc,align='center',font=ziti) # 显示歌词writer.screen.ontimer(display_lrc,septime) # 时间到显示下一句lrc_index = lrc_index + 1            # 索引加1 display_lrc()        class Snow(Turtle): def __init__(self):        Turtle.__init__(self,shape='dot',visible=False)self.penup()self.color("white")                       # 雪花颜色self.sh = self.screen.window_height()     # 屏幕高度self.sw = self.screen.window_width()      # 屏幕宽度self.init()def init(self):self.ht()                                 # 隐藏自己x = randint(-self.sw//2,self.sw//2)       # 设置x坐标y = randint(self.sh,self.sh*2)            # 设置y坐标self.goto(x,y)                            # 坐标定位self.xspeed = randint(-1,1)               # 横向速度self.yspeed = randint(-2,-1)              # 垂直速度self.st()                                 # 显示自己def move(self):"""根据x和y速度移动"""x = self.xcor() + self.xspeed   # 水平坐标增加横向速度y = self.ycor() + self.yspeed   # 垂直坐标增加垂直速度   self.goto(x,y)         if y < -self.sh//2 :            # 到屏幕最低就重新initself.init()def close_window():"""单击屏幕把running设为False,这样while循环就结束了"""global running    if messagebox.askokcancel("白桦林", "你真的要离开吗?"):running = Falseif __name__ == "__main__":counter = 0                         # 计数器变量amounts = 150                       # 设定粒子总数width,height = 480,360              # 定义屏幕宽高running = True                      # 运行标志screen = Screen()                   #  新建屏幕screen.addshape("dot",((0,0),(0,0)))# 设定dot形状screen.setup(width,height)          # 设定屏幕宽高screen.bgcolor("black")             # 设定屏幕背景screen.bgpic("bg.png")              # 设定背景图片screen.title("白桦林的故事_程序制作:李兴球")# 设定标题   screen.delay(0)                     # 设定屏幕延时screen.onclick(lambda x,y:close_window()) # 单击屏幕关窗root = screen._root                 # _root继承自Tk类# 下一句表示当按窗口关闭按钮时调用close_window函数root.ondestroy(close_window)     sing("白桦林.wav","白桦林.lrc")     # 显示歌词放音乐    ps = []                             # 定义粒子列表while running:                      # 进入循环if counter < amounts:           # 未达指定数量p = Snow()                   # 生成雪花粒子ps.append(p)                 # 添加到列表counter += 1                 # 计数器加一                             [p.move() for p in ps]          # 移动每个粒子screen.update()                 # 屏幕刷新重画root.destroy()                      # 销毁窗口

无图无真相,要看作品的显示内容,请加本人抖音号即可!13507998321. ,在手机号后面有一个点!本人欲打造原创博客,域名就是我的名字lixingqiu.com。你可以收藏一下,敬请期待。

《哪咤学python进阶篇》之选学案例三:白桦林的故事_(Python多媒体MV)相关推荐

  1. python进阶篇:如何进行存档!粉丝特辑!

    python进阶篇:如何进行存档!粉丝特辑! 大家好!制作不易,请求赞赏! 大家一般在制作游戏的时候,都很想制作存档这个功能,但到底怎么做呢? 下面就告诉大家! 1.1基本文件操作 为什么要学这个呢? ...

  2. 三步解决C语言中struct字节对齐问题,Python进阶篇-struct字节对齐问题

    Python进阶篇-struct字节对齐问题 Python进阶篇-struct字节对齐问题 Python调用C的时候,会传递一些复杂的数据结构,例如结构体,这时候就会遇到各种各样字节对齐的问题.下边所 ...

  3. Python进阶篇:百度指数解密【抓包JS逆向数据区分】

    前言 大家好,我是辣条哥~ 过往给大家更新了不少基础相关的,今天给大家上点硬货,基础不好的慎入,免得打击你们的积极性~ 其次对数据分析|数据可视化|pandas感兴趣的可以来这里刷刷题: →→→< ...

  4. 伍六七带你学算法 进阶篇-生命游戏

    有趣的算法题–生命游戏 难度-中等 根据 百度百科 ,生命游戏,简称为生命,是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机. 想要体验生命游戏的小伙伴可以到这里-->生命游戏 进入 ...

  5. python(进阶篇)——自动化操作Excel(xlrd和xlwt)

    活动地址:CSDN21天学习挑战赛 学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩: 虽然永远无法预料明天是晴还是雨, 也无法预知你在乎的人是否还在身旁, 以及你一直以来的坚持究竟能否换来什么. ...

  6. Python进阶篇:MySQL隔离级别详解

    前言 数据库并发的对同一批数据进行增删改,就可能会出现我们所说的脏写.脏读.不可重复读.幻读等一系列问题.MySQL提供了一系列机制来解决事务并发问题,比如事务隔离.锁机制.MVCC多版本并发控制机制 ...

  7. Python进阶篇:百度指数解密【抓包|JS逆向|数据区分】

    前言 大家好,我是辣条哥~ 过往给大家更新了不少基础相关的,今天给大家上点硬货,基础不好的慎入,免得打击你们的积极性~ 其次对数据分析|数据可视化|pandas感兴趣的可以来这里刷刷题: →→→< ...

  8. 伍六七带你学算法 进阶篇-排序算法

    给定一个整数数组 nums,将该数组升序排列. 示例 1: 输入:[5,2,3,1] 输出:[1,2,3,5] 示例 2: 输入:[5,1,1,2,0,0] 输出:[0,0,1,1,2,5] 各排序算 ...

  9. 伍六七带你学算法 进阶篇-三数之和

    三数之和 难度-中等 题目:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组. 注意 ...

  10. [Python公开课]零基础玩转Python进阶篇----第九节:Python的异常分析及解决

最新文章

  1. datagrid底部显示水平滚动_easyUI datagrid 横向滚动条显示问题
  2. Mac再建管理员帐户
  3. 【转】VTK修炼之道2_VTK体系结构1
  4. Vue或React多页应用脚手架
  5. 分享一些自己的学习过程和学习方法
  6. vs 2017 无法安装任何 nuget package,提示“库没有注册。。。”
  7. 链接生成动态二维码图片显示在页面上
  8. JQuery官方学习资料(译):类型
  9. Leetcode 513 javascript
  10. matlab中boxplot函数的参数设置_Matlab箱形图boxplot函数用法
  11. 有一群志同道合的程序员朋友是怎样的体验?
  12. 897-了解微服务网关
  13. 人民的名义泄漏版百度云46-56集百度网盘下载
  14. 如何将数据从一台主机发送到另一台主机上(详解)
  15. Excel同一单元格多数据如何求平均数
  16. 西哈努克之子柬埔寨国王西哈莫尼抵京-西哈努克-国王-抵京
  17. esp32cam.cpp:30:3: error: ‘camera_sensor_info_t’ was not declared in this scope camera_sensor_info_t
  18. 语音合成(speech synthesis)方向十一:聊一聊增量式语音合成(iTTS)进化史
  19. SCOI 2012 喵星球上的点名 题解
  20. Vscode 设置clang-format

热门文章

  1. 织梦上传到服务器不显示图像,织梦dede源码前台会员发布文章带图片不显示怎么办?...
  2. python 四象限图_Tableau技巧|制作四象限图
  3. lg、ln的表示方法
  4. R语言 数据操作小贴士合集
  5. 深度学习:GAN 对抗网络原理详细解析(零基础必看)
  6. 抗衡微软,三款国产软件接力金山WPS,身体力行,不愧是国产之光
  7. java枚举处理工具
  8. mysql的分页——limit、offset
  9. 深信服Python笔试
  10. 第八周、第九周学习总结