我們看綜藝的時候,經常能看到現場的提詞板。今天我們就用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,這個我們下次再探討吧!)