Python实现音乐播放器(爬虫、多线程、进度条、文件)
本音乐播放器GUI方面运用Python的tkinter实现,播放的音乐来自网络爬虫和本电脑已经有的。为了使整个程序运行起来不卡顿,运用多线程[不运用多线程会出现卡顿现象,读者可以看看小编之前的文章,里面有一篇是关于Python实现音乐播放器的,当时效果就是出现卡顿]。
说到布局,tkinter提供的有3种,小编使用的是grid布局,这种布局很容易让人理解自己做的一些控件、标签等在整个窗口的位置。
布局 | 说明 |
---|---|
pack() | 按照控件的添加顺序其进行排列,遗憾的是此方法灵活性较差 |
grid() | 以行和列(网格)形式对控件进行排列,此种方法使用起来较为灵活 |
place() | 可以指定组件大小以及摆放位置,三个方法中最为灵活的布局方法 |
整个音乐播放器的效果就是上述那样。
代码有点多,且涉及到文件读写,就不不把代码一一粘贴出来了,想要的读者直接去资源下载即可。
这是其中一部分。
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 jsonclass MusicTk:def __init__(self):self.__top = tk.Tk()self.__size = [1150,700]# 窗口大小 宽 高self.__search2 = Noneself.__listbox = Noneself.__listMusic = Noneself.__mixer = Noneself.__canvas = None# 画布self.__progressBar = None# 进度条self.__time1 = Noneself.__time2 = Noneself.__scale = Noneself.__temp = Noneself.__listInfo = Noneself.__myCollections = Noneself.__data = ['微软雅黑',12,'white','black']self.__cbox = Noneself.__cbox2 = Noneself.__cbox3 = Noneself.__cbox4 = Noneself.__radioBtn = Noneself.__radioBtnV = Noneself.__num1 = 0self.__state = 0self.__keyword = ''self.win2 = None# 布局def sectionOne(self):win = self.__topwin.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('',self.fun1)label_1.bind('',self.fun2)self.__search2 = label_1frame = 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_boxself.__listbox.bind('',func=self.__fun4)# 双击鼠标左键播放音乐self.__listbox.bind('',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 = canvassv = 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("", self.event1)progressBar = ttk.Progressbar(win)# 进度条progressBar.grid(row=2,column=0,columnspan=2)progressBar['length'] = self.__size[0]-400progressBar['value'] = 0# 进度条赋初值为0self.__progressBar = progressBarframe2 = 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_2tk.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_3self.__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 = win2tk.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 = cboxself.__cbox2 = cbox2self.__cbox3 = cbox3self.__cbox4 = cbox4saveBtn = 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'] = fontdict2['size'] = sizedict2['fontColor'] = fontColordict2['bgColor'] = bgColorstr2 = 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 = dict1self.__listbox.delete(0, tk.END)# 清空列表框里的内容for key in dict1:self.__listbox.insert(tk.END, f'{key}')self.__state = 1def __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.__listboxv = 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.__mixermixer.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 = NonelistBox = self.__listboxv = listBox.get(listBox.curselection())dict1 = self.__myCollectionslist1 = dict1[v]self.__keyword = vmusicPlayThread = 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 = listInfomusicPlayThread = 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 = mixerdef threadFun2(self,lyrics):lyrics = lyrics.split('\r\n')canvas = self.__canvascanvas.delete(tk.ALL)canvas.yview_scroll(-2000, 'units')start_time = 0for i in range(len(lyrics)):l = lyrics[i]if l != '' :time1 = l[:10]minute = int(time1[1:3])*60*1000second = int(float(time1[4:9])*1000)sumTime = minute + secondtimeDifference = sumTime - start_timestart_time = sumTimestr1 = 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.__progressBarprogressBar['maximum'] = zTimeprogressBar['value'] = 0for i in range(zTime):if self.__temp is None:progressBar['value'] += 1time.sleep(1)def threadFun4(self,zTime):minute = zTime//60second = zTime - minute*60self.__time2['text'] = '{:02d}:{:02d}'.format(minute,second)minute1 = 0second1 = 0for i in range(zTime+1):if self.__temp is None:if second1!= 0 and second1 == 60:minute1 += 1second1 = 0time.sleep(1)self.__time1['text'] = '{:02d}:{:02d}'.format(minute1,second1)second1 += 1if self.__num1 == 1 and self.__state == 1:dict2 = self.__myCollectionsl = 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 = keywordself.__play()def __getMp3Time(self,randomNum):filePath = f'./musics/{randomNum}.mp3'song = pd.from_file(file = filePath,format = 'mp3')return len(song)//1000def fun2(self,event):if self.__search2 is not None:entry_2 = self.__search2entry_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 = listsself.__listbox.delete(0, tk.END)# 清空列表框里的内容for list2 in lists:self.__listbox.insert(tk.END, f'{list2[1]}-{list2[0]}')self.__state = 0def 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()