文章目录
- 1. 程序运行结果
- 2.程序实现原理
- 3. GUI布局
- 4. 功能介绍
- 5. 代码实现
1. 程序运行结果
Python实现音乐播放器(爬虫、多线程、进度条、文件)
2.程序实现原理
本音乐播放器GUI方面运用Python的tkinter实现,播放的音乐来自网络爬虫和本电脑已经有的。为了使整个程序运行起来不卡顿,运用多线程[不运用多线程会出现卡顿现象,读者可以看看小编之前的文章,里面有一篇是关于Python实现音乐播放器的,当时效果就是出现卡顿]。
3. GUI布局
说到布局,tkinter提供的有3种,小编使用的是grid布局,这种布局很容易让人理解自己做的一些控件、标签等在整个窗口的位置。
布局 | 说明 |
---|---|
pack() | 按照控件的添加顺序其进行排列,遗憾的是此方法灵活性较差 |
grid() | 以行和列(网格)形式对控件进行排列,此种方法使用起来较为灵活 |
place() | 可以指定组件大小以及摆放位置,三个方法中最为灵活的布局方法 |
4. 功能介绍
整个音乐播放器的效果就是上述那样。
- 如果要搜索线上音乐,直接在搜索框里输入歌名,然后按电脑键盘的Enter,然后搜索框下面的列表框里就会给出搜索的结果,如果想听其中的一首,鼠标点击到那一首歌曲那然后双击鼠标左键,即可播放音乐。如果我们想把播放的音乐收藏,直接点击鼠标右键即可;
- 如果我们想听我的收藏里的歌曲,直接点击我的收藏,然后列表框里的内容就会变成已经收藏的音乐,此时不是双击鼠标左键进行播放,而是选中其中一首,然后点击下面的播放按钮进行播放,如果我们想要歌曲循环播放,点击下面的循环播放即可(注:循环播放只支持收藏的音乐);
- 调节音量的大小,使用Scale控件(循环播放前面那个玩意);
- 设置按钮可以用来设置歌词的字体颜色、字体大小、字体格式和背景颜色,用的是下拉框,设置之后,保存即可。
5. 代码实现
代码有点多,且涉及到文件读写,就不不把代码一一粘贴出来了,想要的读者直接去资源下载即可。
这是其中一部分。
import tkinter as tk
import tkinter.ttk as ttk
from Crawl2.music_player.MusicCrawl import MusicCrawl
import threading
import time
from pydub import AudioSegment as pd
from pygame import mixer
import json
class MusicTk:
def __init__(self):
self.__top = tk.Tk()
self.__size = [1150,700]
# 窗口大小 宽 高
self.__search2 = None
self.__listbox = None
self.__listMusic = None
self.__mixer = None
self.__canvas = None
# 画布
self.__progressBar = None
# 进度条
self.__time1 = None
self.__time2 = None
self.__scale = None
self.__temp = None
self.__listInfo = None
self.__myCollections = None
self.__data = ['微软雅黑',12,'white','black']
self.__cbox = None
self.__cbox2 = None
self.__cbox3 = None
self.__cbox4 = None
self.__radioBtn = None
self.__radioBtnV = None
self.__num1 = 0
self.__state = 0
self.__keyword = ''
self.win2 = None
# 布局
def sectionOne(self):
win = self.__top
win.geometry(f'{self.__size[0]}x{self.__size[1]}')
win.resizable(height=0,width=0)
v = tk.StringVar(value="搜索音乐")
label_1 = tk.Entry(win,textvariable=v, font=('微软雅黑', 12),width=24)
label_1.grid(row=0, column=0,ipady=2,ipadx=2,padx=20,sticky=tk.W)
# 搜索框
label_1.bind('<ButtonPress-1>',self.fun1)
label_1.bind('<Return>',self.fun2)
self.__search2 = label_1
frame = tk.Frame(win)
frame.grid(row=0, column=1, sticky=tk.W)
tk.Button(frame, text='我的收藏',font=('', 12),command=self.__myCollection).grid(row=0, column=0, ipadx=1, ipady=1, sticky=tk.W)
# 我的收藏 按钮
tk.Button(frame,text='设置',font=('', 12),command=self.__setButton).grid(row=0,column=1,ipadx=1,ipady=1,padx=2,sticky=tk.W)
# 设置按钮
frameMiddle = tk.Frame(win)
frameMiddle.grid(row=1,column=0,columnspan=2)
list_box = tk.Listbox(frameMiddle, font=('', 12,'bold'), width=30,height=35,selectmode="single",selectbackground='red')
list_box.grid(row=0, column=0)
self.__listbox = list_box
self.__listbox.bind('<Double-Button-1>',func=self.__fun4)
# 双击鼠标左键播放音乐
self.__listbox.bind('<ButtonPress-3>',func=self.__restore)
# 单击鼠标右键收藏音乐
canvas = tk.Canvas(frameMiddle,bg=self.__data[3],width=900,height=600,confine=True,relief='groove')
canvas.grid(row=0,column=1)
# 画布
self.__canvas = canvas
sv = tk.Scrollbar(frameMiddle)
sv.grid(row=0, column=2)
canvas.config(yscrollcommand=sv.set)
canvas.config(scrollregion=(0, 0, 900, 3000))
sv.config(command=canvas.yview)
canvas.config(yscrollincrement=1)
canvas.bind("<MouseWheel>", self.event1)
progressBar = ttk.Progressbar(win)
# 进度条
progressBar.grid(row=2,column=0,columnspan=2)
progressBar['length'] = self.__size[0]-400
progressBar['value'] = 0
# 进度条赋初值为0
self.__progressBar = progressBar
frame2 = tk.Frame(win)
frame2.grid(row=3,column=0,columnspan=2)
label_2 = tk.Label(frame2,text='00:00',font=('',12))
label_2.grid(row=0,column=0,sticky=tk.W)
self.__time1 = label_2
tk.Button(frame2,text='上一首',font=('',12)).grid(row=0,column=1)
tk.Button(frame2, text='播放',font=('',12),command=self.__play).grid(row=0, column=2)
tk.Button(frame2, text='暂停',font=('',12),command=self.__stop).grid(row=0, column=3)
tk.Button(frame2, text='下一首', font=('', 12)).grid(row=0, column=4)
label_3 = tk.Label(frame2, text='00:00', font=('', 12))
label_3.grid(row=0, column=5, sticky=tk.E)
self.__time2 = label_3
self.__scale = tk.Scale(frame2,from_=0,to=100,resolution=2,length=150,orient=tk.HORIZONTAL,font=('',12),command=self.fun6)
self.__scale.grid(row=0,column=6,sticky=tk.E,padx=10)
self.__scale.set(100)
self.__radioBtnV = tk.IntVar()
self.__radioBtn = tk.Checkbutton(frame2,variable=self.__radioBtnV,text='循环播放',onvalue=1,command=self.__getRadioBtn)
self.__radioBtn.grid(row=0,column=7,sticky=tk.E,padx=10)
# 复选框
tk.mainloop()
def __getRadioBtn(self):
self.__num1 = self.__radioBtnV.get()
# 设置按钮
def __setButton(self):
win2 = tk.Tk()
self.win2 = win2
tk.Label(win2,text='播放字体',font=('微软雅黑',10)).grid(row=0,column=0)
# 下拉框
cbox = ttk.Combobox(win2)
cbox.grid(row=0,column=1)
cbox['value'] = ('微软雅黑','华文宋体','华文宋体')
cbox.current(0)
tk.Label(win2,text='字体大小',font=('微软雅黑',10)).grid(row=1,column=0)
cbox2 = ttk.Combobox(win2)
cbox2.grid(row=1, column=1)
cbox2['value'] = tuple([str(i) for i in range(12,19)])
cbox2.current(0)
tk.Label(win2, text='字体颜色', font=('微软雅黑', 10)).grid(row=2, column=0)
cbox3 = ttk.Combobox(win2)
cbox3.grid(row=2, column=1)
cbox3['value'] = ('white','red','black')
cbox3.current(0)
tk.Label(win2, text='背景颜色', font=('微软雅黑', 10)).grid(row=3, column=0)
cbox4 = ttk.Combobox(win2)
cbox4.grid(row=3, column=1)
cbox4['value'] = ('black','white')
cbox4.current(0)
self.__cbox = cbox
self.__cbox2 = cbox2
self.__cbox3 = cbox3
self.__cbox4 = cbox4
saveBtn = tk.Button(win2,text='保存',font=('微软雅黑',10),command=self.__reset)
saveBtn.grid(row=4,column=0,columnspan=2)
win2.mainloop()
def __reset(self):
font = self.__cbox.get()
size = self.__cbox2.get()
fontColor = self.__cbox3.get()
bgColor = self.__cbox4.get()
self.__data = [font,size,fontColor,bgColor]
dict2 = dict()
dict2['font'] = font
dict2['size'] = size
dict2['fontColor'] = fontColor
dict2['bgColor'] = bgColor
str2 = json.dumps(dict2)
with open(file='data.json',mode='w',encoding='utf-8') as f:
f.write(str2)
self.win2.destroy()
# 我的收藏按钮
def __myCollection(self):
with open(file='Collection.json',mode='r',encoding='utf-8') as f:
str_1 = f.read()
dict1 = json.loads(str_1)
self.__myCollections = dict1
self.__listbox.delete(0, tk.END)
# 清空列表框里的内容
for key in dict1:
self.__listbox.insert(tk.END, f'{key}')
self.__state = 1
def __restore(self,event):
with open(file='Collection.json',mode='r',encoding='utf-8') as f:
str1 = f.read()
if str1 != '':
dict1 = json.loads(str1)
else:
dict1 = {}
listBox = self.__listbox
v = listBox.get(listBox.curselection())
if v not in dict1:
dict1[v] = [self.__listInfo[1],self.__listInfo[2],self.__listInfo[3]]
str1 = json.dumps(dict1)
with open(file='Collection.json',mode='w',encoding='utf-8') as f:
f.write(str1)
def fun6(self,value):
if self.__mixer is not None:
mixer = self.__mixer
mixer.music.set_volume(int(value)/100)
def event1(self,event):
number = int(-event.delta / 60)
self.__canvas.yview_scroll(number, 'units')
def __play(self):
# if self.__mixer is not None:
# self.__mixer.music.unpause()
# self.__temp = None
listBox = self.__listbox
v = listBox.get(listBox.curselection())
dict1 = self.__myCollections
list1 = dict1[v]
self.__keyword = v
musicPlayThread = threading.Thread(target=self.threadFun1, args=([True,0,0,list1[2]],))
lyricsThread = threading.Thread(target=self.threadFun2, args=(list1[0],))
progressThread = threading.Thread(target=self.threadFun3, args=(list1[1],))
timeThread = threading.Thread(target=self.threadFun4, args=(list1[1],))
musicPlayThread.start()
lyricsThread.start()
progressThread.start()
timeThread.start()
def __stop(self):
if self.__mixer is not None:
# self.__mixer.music.stop()
self.__mixer.music.pause()
self.__temp = 'stop'
def __fun4(self,event):
tuple2 = self.__listbox.curselection()
if len(tuple2) != 0:
index = tuple2[0]
url = self.__listMusic[index][-1]
# thread2 = threading.Thread(target=self.fun5,args=(url,))
# thread2.start()
self.fun5(url)
def fun5(self,url):
mC = MusicCrawl('我的梦')
listInfo = mC.DownLoad(url)
# mp3Time = self.__getMp3Time(listInfo[3])
self.__listInfo = listInfo
musicPlayThread = threading.Thread(target=self.threadFun1,args=(listInfo,))
lyricsThread = threading.Thread(target=self.threadFun2,args=(listInfo[1],))
progressThread = threading.Thread(target=self.threadFun3,args=(listInfo[2],))
timeThread = threading.Thread(target=self.threadFun4,args=(listInfo[2],))
musicPlayThread.start()
lyricsThread.start()
progressThread.start()
timeThread.start()
# 线程函数
def threadFun1(self,listInfo:list):
if listInfo[0]:
mixer.init()
mixer.music.load(f'./musics/{listInfo[3]}.mp3')
mixer.music.play()
#
self.__mixer = mixer
def threadFun2(self,lyrics):
lyrics = lyrics.split('\r\n')
canvas = self.__canvas
canvas.delete(tk.ALL)
canvas.yview_scroll(-2000, 'units')
start_time = 0
for i in range(len(lyrics)):
l = lyrics[i]
if l != '' :
time1 = l[:10]
minute = int(time1[1:3])*60*1000
second = int(float(time1[4:9])*1000)
sumTime = minute + second
timeDifference = sumTime - start_time
start_time = sumTime
str1 = l[10:]
time.sleep(timeDifference/1000)
canvas.create_text(30, 20 + i * 20, text=f'{str1}', fill=self.__data[2], anchor=tk.W,
font=(self.__data[0], self.__data[1], 'bold'))
if 20+i*20 > 550:
for j in range(10):
canvas.yview_scroll(2, 'units')
def threadFun3(self,zTime):
progressBar = self.__progressBar
progressBar['maximum'] = zTime
progressBar['value'] = 0
for i in range(zTime):
if self.__temp is None:
progressBar['value'] += 1
time.sleep(1)
def threadFun4(self,zTime):
minute = zTime//60
second = zTime - minute*60
self.__time2['text'] = '{:02d}:{:02d}'.format(minute,second)
minute1 = 0
second1 = 0
for i in range(zTime+1):
if self.__temp is None:
if second1!= 0 and second1 == 60:
minute1 += 1
second1 = 0
time.sleep(1)
self.__time1['text'] = '{:02d}:{:02d}'.format(minute1,second1)
second1 += 1
if self.__num1 == 1 and self.__state == 1:
dict2 = self.__myCollections
l = list(dict2.keys())
index = l.index(self.__keyword)
keyword = l[(index+1)%len(l)]
self.__listbox.selection_clear(0, tk.END)
self.__listbox.selection_set((index+1)%len(l))
self.__keyword = keyword
self.__play()
def __getMp3Time(self,randomNum):
filePath = f'./musics/{randomNum}.mp3'
song = pd.from_file(file = filePath,format = 'mp3')
return len(song)//1000
def fun2(self,event):
if self.__search2 is not None:
entry_2 = self.__search2
entry_value = entry_2.get()
# 输入框里的值
if len(entry_value.strip()) != 0:
self.fun3(entry_value)
# thread1 = threading.Thread(target=self.fun3,args=(entry_value,))
# thread1.start()
def fun3(self,keyWord):
mC = MusicCrawl(keyWord)
lists = mC.crawlSection()
# print(lists)
self.__listMusic = lists
self.__listbox.delete(0, tk.END)
# 清空列表框里的内容
for list2 in lists:
self.__listbox.insert(tk.END, f'{list2[1]}-{list2[0]}')
self.__state = 0
def fun1(self,event):
if self.__search2 is not None:
self.__search2.delete(0,'end')
# 一个监听事件的函数
def sectionTwo(self):
# 操作
with open(file='data.json',mode='r',encoding='utf-8') as f:
str2 = f.read()
dict2 = json.loads(str2)
self.__data = [dict2['font'],dict2['size'],dict2['fontColor'],dict2['bgColor']]
self.sectionOne()
if __name__ == '__main__':
a = MusicTk()
a.sectionTwo()