https://blog.csdn.net/qq_41962782/article/details/80106158
小弟是小白因大作业,在此博文的基础上,我增加了歌曲目录的选择,自动播放,实时显示歌词名称并能实现自动切歌的功能,后续可能会增加一下实时显示动态歌词,歌曲下载等功能。于是写一篇博客记录一下。望大神指教!
自动播放的关键在于用多线程编程来跳出自动播放在GUI界面设计中死循环!
废话不多说,代码如下:
main_test.py
import tkinter
import os
from musicTree import TreeWindows
from lyric import Lyric
from musicButton import MusicButton
import sys, time
from tkinter.filedialog import askdirectory
sys.path.append('/Users/wangrui/PycharmProjects/pythonProject/final homework/music')
win = tkinter.Tk()
win.title("何猪音乐播放器")
win.geometry("950x700+300+100")
# path = r"/Users/wangrui/Downloads/test"
path = askdirectory()
frameL = tkinter.Frame(win)
frameL.pack(fill=tkinter.Y, side=tkinter.LEFT)
frameR = tkinter.Frame(win)
frameR.pack(fill=tkinter.Y, side=tkinter.RIGHT)
treeWin = TreeWindows(frameL, path)
button = MusicButton(frameR, path)
win.mainloop()
目录选择的根本在于askdirectory函数。
musicButton.py
import tkinter
import threading
import os
import pygame
import random
import time
from mutagen.mp3 import MP3
# path = r"/Users/wangrui/Downloads/test"
num=0
class MusicButton(tkinter.Frame):
def __init__(self, master, path):
self.path = path
frame = tkinter.Frame(master)
frame.pack(side=tkinter.TOP, fill=tkinter.X)
self.label = tkinter.Label(frame)
self.label.pack(fill=tkinter.X, side=tkinter.TOP)
self.button1 = tkinter.Button(frame,
text="上一曲",
command=self.func1,
width=10,
height=4,
bg="blue",
fg="red",
font=("华文琥珀", 10))
self.button1.pack(side=tkinter.BOTTOM)
self.button2 = tkinter.Button(frame,
text="播放",
command=self.func2,
width=10,
height=4,
bg="blue",
fg="red",
font=("华文琥珀", 10))
self.button2.pack(side=tkinter.BOTTOM)
self.button3 = tkinter.Button(frame,
text="暂停",
command=self.func3,
width=10,
height=4,
bg="blue",
fg="red",
font=("华文琥珀", 10))
self.button3.pack(side=tkinter.BOTTOM)
self.button4 = tkinter.Button(frame,
text="下一曲",
command=self.func4,
width=10,
height=4,
bg="blue",
fg="red",
font=("华文琥珀", 10))
self.button4.pack(side=tkinter.BOTTOM)
self.button5 = tkinter.Button(frame,
text="自动播放",
command=self.func5,
width=10,
height=4,
bg="blue",
fg="red",
font=("华文琥珀", 10))
self.button5.pack(side=tkinter.BOTTOM)
self.label = tkinter.Label(frame,
text="HELLO 这里是 ARVIN 音乐播放器 ……",
bg="light green",
fg="blue")
self.label.pack(fill=tkinter.X, side=tkinter.BOTTOM)
self.label = tkinter.Label(frame,
text="这里可以实时显示歌曲名称哦",
bg="blue",
fg="white",
font=("华文琥珀", 20))
self.label.pack(fill=tkinter.X)
self.txt = tkinter.Text(frame,
width=100,
height=50,
bg="light blue",
fg="blue")
self.txt.pack(side=tkinter.TOP, fill=tkinter.X)
def file_name(self):
for root, dirs, files in os.walk(self.path):
return files
def func1(self):
global playing
global num
res=[]
self.txt.delete(1.0,"end")
file = self.file_name()
for x in file:
(filename1, extension) = os.path.splitext(x)
if extension == '.mp3':
res.append(os.path.join(self.path, x))
palying = False
pygame.mixer.music.stop()
if num == 0:
num = len(res) - 2
elif num == len(res) - 1:
num -= 2
else:
num -= 2
playing = True
# 必须创建一个线程来播放音乐,当前主线程来接收用户操作
t = threading.Thread(target=self.play)
# start执行线程
t.start()
def func2(self):
# pygame.mixer.music.play()
pygame.mixer.music.unpause()
def func3(self):
pygame.mixer.music.pause()
def func4(self):
global playing
global num
self.txt.delete(1.0,"end")
res = []
file = self.file_name()
for x in file:
(filename1, extension) = os.path.splitext(x)
if extension == '.mp3':
res.append(os.path.join(self.path, x))
palying = False
pygame.mixer.music.stop()
if len(res) == num:
num = 0
playing = True
# 必须创建一个线程来播放音乐,当前主线程来接收用户操作
t = threading.Thread(target=self.play)
# start执行线程
t.start()
def func5(self):
global playing
self.txt.delete(1.0,"end")
playing = True
t = threading.Thread(target=self.cycle_play)
t.start()
def getPath(self,path1):
pathList = os.path.split(path1)
return pathList[-1]
def play(self):
# 播放音乐
# 混音初始化,num给播放的歌创建id
res = []
file = self.file_name()
for x in file:
(filename1, extension) = os.path.splitext(x)
if extension == '.mp3':
res.append(os.path.join(self.path, x))
if len(res):
pygame.mixer.init()
global num
global playing
while playing:
if not pygame.mixer.music.get_busy():
self.txt.delete(1.0, "end")
# 随机播放一首歌曲
nextMusic = res[num]
pygame.mixer.music.load(nextMusic)
audio = MP3(nextMusic)
pygame.mixer.music.play()
self.txt.insert(tkinter.INSERT, nextMusic) # 测试代码
if len(res) - 1 == num:
num = 0
else:
num = num + 1
playing =True
nextMusic = nextMusic.split('\\')[1:]
# musicName.set('playing......' + ''.join(nextMusic))
else:
time.sleep(0.1)
def cycle_play(self):
global playing
global filename1
try:
list1=[]
# list1 = os.listdir(self.path)
for x in os.listdir(self.path):
# absPath = os.path.join(self.path, x)
# text = self.getPath(absPath)
(filename1, extension) = os.path.splitext(x)
if extension == '.mp3':
list1.append(x)
list2 = []
for i in list1:
s = os.path.join(self.path, i)
list2.append(s)
a=0
while a<len(list2):
for n in list2:
# 获取每一首歌的时长
path = n
audio = MP3(n)
pygame.mixer.init() # 初始化所有引入的模块
# self.txt.delete(1.0, "end") #test
pygame.mixer.music.load(path) #载入音乐
pygame.mixer.music.play() # 播放载入的音乐
print(filename1)
self.txt.insert(tkinter.INSERT, path) #测试代码
time.sleep(int(audio.info.length)) # 获取每一首歌曲的时长,使程序存活的时长等于歌曲时长
playing = True
t = threading.Thread(target=self.play)
t.start()
self.txt.delete(1.0, "end")
a+=1
except Exception as e:
print("Exception: %s" % e)
其中cycle_play是自动播放函数,在fun5中使用多线程调用了这个函数,使得可以通过外部指令打破自动播放中的for死循环。
musicTree.py
import tkinter
from tkinter import ttk
import os
import time
import pygame
class TreeWindows(tkinter.Frame):
def __init__(self, master, path):
self.path = path #define path to global variable
frame = tkinter.Frame(master) # father initialization
frame.pack(side=tkinter.LEFT, fill=tkinter.Y)
self.label = tkinter.Label(frame, #创建控件
text="曲库",
bg="blue",
fg="white",
font=("华文琥珀", 15))
self.label.pack(fill=tkinter.X)
self.tree = ttk.Treeview(frame) #构建文件管理器
self.tree.pack(fill=tkinter.Y, side=tkinter.LEFT)
# text=os.path.splitext() #将路径最后一级分离出来 windows不支持
root = self.tree.insert("", "end", text=self.getPath(path), open=True, values=(path))
# 加载所有树枝
self.loadTree(root, path)
# 添加滚动条
self.sy = tkinter.Scrollbar(frame)
self.sy.pack(side=tkinter.RIGHT, fill=tkinter.Y)
self.sy.config(command=self.tree.yview) #配置滚动条对应到文本框
self.tree.config(yscrollcommand=self.sy.set)
# 绑定事件
self.tree.bind("<<TreeviewSelect>>", self.func) #将函数func的调用以事件顺序绑定到这个小部件
def func(self, event):
self.v = event.widget.selection() #event.widget获取Treeview对象,调用selection获取选择对象名称
for sv in self.v:
file = self.tree.item(sv)["text"]
absPath = os.path.join(self.path, file)
pygame.mixer.init()
# track = pygame.mixer.music.load(absPath)
# pygame.mixer.music.play()
if absPath != r"/Users/wangrui/Downloads/test":
track = pygame.mixer.music.load(absPath)
pygame.mixer.music.play()
def loadTree(self, father, fatherPath):
# 遍历所有目录
for filename in os.listdir(fatherPath):
absPath = os.path.join(fatherPath, filename)
# 插入树枝
treey = self.tree.insert(father, "end", text=self.getPath(absPath), values=(absPath))
# 判断是否是目录
if os.path.isdir(absPath):
# 递归
self.loadTree(treey, absPath)
def getPath(self, path):
pathList = os.path.split(path)
return pathList[-1]
先对歌曲目录进行选择~~~~
然后GUI界面如下,有自动播放,上一曲,下一曲,播放,暂停功能。
我们播放一首歌试试~~点击自动播放按钮,音乐就开始播放啦,并且能实时显示歌曲名称和根目录~~
完结,撒花~~以后可能会增加一些歌词动态实时显示,图片作为背景插入循环显示,随机播放等等功能~~
小弟刚接触python,有什么写得有问题的地方,望大神指教。