我们看综艺的时候,经常能看到现场的提词板。今天我们就用tkinter做一个简单的提词板,用到了tkinter的label来动态显示文字。

我们就以最近火爆的《想见你》这首歌为例,按照歌词时间来显示歌词。首先我们要准备好歌词文件,一般是lrc的格式,每句歌词前面都有时间,随便去网上找一个,存成txt即可。

歌词文本是这样的:

我们只要分割每行的时间和歌词,然后根据时间更新下一句歌词就行了。由于格式是固定的,为了简便,按照固定位置截取即可,每一行都是从索引11开始为歌词,索引1-9是时间。

下面是主要的算法函数,用按钮来触发:

def showLrc():
    start = time.time()  #按下按钮开始计时,用于判断时间
    i=""
    for j in range(len(f)):
        lrc = f[j].decode().strip()  #lrc为当前这一行的内容      
        for k in range(11,len(lrc)):
            i+=lrc[k]  #每次刷新增加一个字
            #一共两行,用两个label来显示歌词
            if j%2==0:
                mes0.config(text=str(i),font=('黑体', 25),fg='Goldenrod')
            else:
                mes1.config(text=str(i),font=('黑体', 25),fg='Goldenrod')       
            time.sleep(0.1)  #每隔0.1秒刷新一次
            top.update_idletasks()  #更新界面      
        i=""
        #读取下一行的时间,即下一句歌词开始的时间点ti
        if j+1 < len(f):
            lrc = f[j+1].decode().strip()
            m = 10*int(lrc[1]) + int(lrc[2])  #分钟
            s = 10*int(lrc[4]) + int(lrc[5])  #秒
            ms = 100*int(lrc[7]) + 10*int(lrc[8]) + int(lrc[9])  #毫秒
            ti = m*60 + s + ms/1000
            second = time.time() - start
            #如果当前计时未到ti,则休眠两个时间的差值
            if second<ti:
                time.sleep(ti-second)
        #用空白来覆盖之前的文本,否则前后两次的文本会重合;
        #注意这里的顺序和之前相反,才能实现交替更新
        if j%2==0:
            mes1.config(text="                                                 ",font=('黑体', 25),fg='Goldenrod')
        else:
            mes0.config(text="                                                 ",font=('黑体', 25),fg='Goldenrod')
        top.update_idletasks()

下面是完整的代码:

import re
import time
from tkinter import *

top = tkinter.Tk()
top.title('提词板')
top.geometry(800x100)
f = open('C:/Users/lin042/Desktop/歌词.txt','rb').readlines()
for i in range(2):
    exec("mes{} = tkinter.Label(text='')".format(i))
    exec('mes{}.pack()'.format(i))

    
def showImg():
    start = time.time()
    i=""
    for j in range(len(f)):
        lrc = f[j].decode().strip()       
        for k in range(11,len(lrc)):
            i+=lrc[k]
            if j%2==0:
                mes0.config(text=str(i),font=('黑体', 25),fg='Goldenrod')
            else:
                mes1.config(text=str(i),font=('黑体', 25),fg='Goldenrod')       
            time.sleep(0.1)
            top.update_idletasks()
       
        i=""
        if j+1 < len(f):
            lrc = f[j+1].decode().strip()
            m = 10*int(lrc[1]) + int(lrc[2])
            s = 10*int(lrc[4]) + int(lrc[5])
            ms = 100*int(lrc[7]) + 10*int(lrc[8]) + int(lrc[9])
            ti = m*60 + s + ms/1000
            second = time.time() - start
            if second<ti:
                time.sleep(ti-second)
        if j%2==0:
            mes1.config(text="                                                 ",font=('黑体', 25),fg='Goldenrod')
        else:
            mes0.config(text="                                                 ",font=('黑体', 25),fg='Goldenrod')
        top.update_idletasks()

submit_button = tkinter.Button(top, text ="想见你", font=('黑体', 10),fg='red',width=10,height=2,command = showImg)
submit_button.place(x=10, y=10)
top.mainloop()

注意这个语句:

for i in range(2):
  exec("mes{} = tkinter.Label(text='')".format(i))
  exec("mes{}.pack()".format(i))

  exec用于创建动态的变量名,这里虽然只有两个label的变量,但如果想多行显示的话,就不能一个一个地声明,用这个方法想创建多少个都可以。

好的,感觉看看成果吧 !!! 

打开手机里的音乐,试试能不能对得上歌词吧。

不过这程序运行起来以后,由于程序一直在循环里面跑,不能再动电脑,也不能同时运行其他软件,否则所有动态效果都会卡住,直到歌词全部更新完。

也许这个提词板挺没用的,但用tkinter动态更新文字的方法,记下来也不亏。比如我们还可以用它来做一个抽奖的滚动画面,或者点名(只能实现动态效果,想要外界终止,需要用到after方法和StringVar,这个我们下次再探讨吧!)