python+tkinter+threading制作多线程简易音乐播放器(自动播放,上一曲,下一曲,播放,暂停,实时显示歌曲名并能自动切换歌曲的功能)

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]

xuanze

先对歌曲目录进行选择~~~~

在这里插入图片描述
然后GUI界面如下,有自动播放,上一曲,下一曲,播放,暂停功能。

我们播放一首歌试试~~点击自动播放按钮,音乐就开始播放啦,并且能实时显示歌曲名称和根目录~~
在这里插入图片描述
完结,撒花~~以后可能会增加一些歌词动态实时显示,图片作为背景插入循环显示,随机播放等等功能~~
小弟刚接触python,有什么写得有问题的地方,望大神指教。

  • 6
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值