音乐盒项目,本地音乐播放器。python和Mysql数据库交互实战项目。运用pygame音乐模块,和Mysql数据库提取存储功能,以及python中的tkinter模块等内容实现

基础ui架构用的python中的tk模块

歌曲储存和提取用的Mysql数据库

歌曲播放等功能用高度python中的pgame模块

目录

软件功能介绍

登录界面

功能界面

完整代码

运行本地音乐盒需要预先准备的环境


软件功能介绍

更新日志:
1,添加了登录和注册的ui界面,不需要再在pyton后端登录啦。
    1.1,登录ui界面成功之后,才能进入音乐播放器界面;
    1.2,添加了注册功能,注册的账号和密码会添加到用户表这个数据库中,并且在表中一并加上注册的时间;
    1.3,对注册进行了优化,对登录界面进行了优化
    1.4,后端优化,注册名字和密码的格式
    1.5,前端增加登录和注册的提示,显示用户的操作
    1.6,设置当前登录注册ui界面不可随意改变
    1.7,添加了登录界面的背景图片
    1.8,优化了登录界面按钮的背景颜色
    1.9,优化了登录界面提示信息的背景颜色
    1.10,新增了登录界面的提示文字
2,优化了播放器的ui界面,
    2.1,前端新增了返回登录的按钮,并且后端实现了返回登录界面的功能
    2.2,扩充了播放歌曲的显示列表,使列表变的更加美观
    2.3,新增了播放列表的滚动滑条,
    2.3,新增了修改音量+和音量-的的按钮;并且后端实现了音量增加和减少的功能
    2.4,前端新增了【暂停】的按钮,并实现了后端暂停播放的功能
    2.5,前端新增了【继续播放】的按钮,并实现了后端继续播放的功能
    2.6,前端新增了【下一曲】的按钮,并实现了后端开启下一首播放的功能;
    2.7,前端新增了【上一曲】的按钮,并实现了后端开启上一首播放的功能;
    2.8,新增了【返回登录】按钮,并实现了后端返回登录界面的功能;
    2.9,以上功能都添加了前端文字提示,并且在后端对照用户的操作,一一给出提示。
    2.10,设置当前播放器ui界面不可随意改变
    2.11,新增了播放器的背景图片
    2.12,优化了播放界面的布局
    2.13,新增了进入播放器后的提示文字   
3,优化了播放列表的显示功能
    3.1,播放列表的时候,导入音乐,不会在重复的导入了,永远都是导入最新的导入的歌曲;
    3.2,歌曲可以实现连续播放,随机播放的功能
    3.3,后数据库用户名添加了唯一约束,防止用户名重复,并且给出提示
    3.4,前端添加了单曲循环按钮,后端实现了实现了单曲循环! 好难实现!!!
    3.5,前端实现了列表循环按钮,后端实现了列表循环播放,这个也超级难!!! 之前实现了是卡死,终于在开辟线程解决了
    3.6,前端实现了列表随机循环按钮,后端实现了随机播放,这个最难最难!!!之前卡死,不能随机,随机报错,终于算法解决了,也解决了卡死
    3.7,前端增加了关闭列表循环和关闭随机循环按钮,后端实现了。不然循环开启,子线程就一直在,会卡死报错,所以我们手动分别杀死他们的线程
'''

登录界面

功能界面

具体见代码吧,代码中注释也比较多

完整代码

# encoding=utf-8
#创建数据库 misic_db
#直接通过第三方途径创建,当然也可以自己编写代码实现
import random
import sys
import threading
import time
import tkinter
from multiprocessing import Process
from threading import Thread
import pygame
from tkinter.filedialog import askopenfilenames
import tkinter as tk
import tkinter.messagebox
import tkinter.filedialog
from PIL import ImageTk, Image
from mutagen.mp3 import MP3
import inspect
import ctypes


from PIL import Image as imim

'''
更新日志:
1,添加了登录和注册的ui界面,不需要再在pyton后端登录啦。
    1.1,登录ui界面成功之后,才能进入音乐播放器界面;
    1.2,添加了注册功能,注册的账号和密码会添加到用户表这个数据库中,并且在表中一并加上注册的时间;
    1.3,对注册进行了优化,对登录界面进行了优化
    1.4,后端优化,注册名字和密码的格式
    1.5,前端增加登录和注册的提示,显示用户的操作
    1.6,设置当前登录注册ui界面不可随意改变
    1.7,添加了登录界面的背景图片
    1.8,优化了登录界面按钮的背景颜色
    1.9,优化了登录界面提示信息的背景颜色
    1.10,新增了登录界面的提示文字
2,优化了播放器的ui界面,
    2.1,前端新增了返回登录的按钮,并且后端实现了返回登录界面的功能
    2.2,扩充了播放歌曲的显示列表,使列表变的更加美观
    2.3,新增了播放列表的滚动滑条,
    2.3,新增了修改音量+和音量-的的按钮;并且后端实现了音量增加和减少的功能
    2.4,前端新增了【暂停】的按钮,并实现了后端暂停播放的功能
    2.5,前端新增了【继续播放】的按钮,并实现了后端继续播放的功能
    2.6,前端新增了【下一曲】的按钮,并实现了后端开启下一首播放的功能;
    2.7,前端新增了【上一曲】的按钮,并实现了后端开启上一首播放的功能;
    2.8,新增了【返回登录】按钮,并实现了后端返回登录界面的功能;
    2.9,以上功能都添加了前端文字提示,并且在后端对照用户的操作,一一给出提示。
    2.10,设置当前播放器ui界面不可随意改变
    2.11,新增了播放器的背景图片
    2.12,优化了播放界面的布局
    2.13,新增了进入播放器后的提示文字   
3,优化了播放列表的显示功能
    3.1,播放列表的时候,导入音乐,不会在重复的导入了,永远都是导入最新的导入的歌曲;
    3.2,歌曲可以实现连续播放,随机播放的功能
    3.3,后数据库用户名添加了唯一约束,防止用户名重复,并且给出提示
    3.4,前端添加了单曲循环按钮,后端实现了实现了单曲循环! 好难实现!!!
    3.5,前端实现了列表循环按钮,后端实现了列表循环播放,这个也超级难!!! 之前实现了是卡死,终于在开辟线程解决了
    3.6,前端实现了列表随机循环按钮,后端实现了随机播放,这个最难最难!!!之前卡死,不能随机,随机报错,终于算法解决了,也解决了卡死
    3.7,前端增加了关闭列表循环和关闭随机循环按钮,后端实现了。不然循环开启,子线程就一直在,会卡死报错,所以我们手动分别杀死他们的线程
'''
#********************************************
# 代码实现
import pymysql



#创建数据库:
def create_database():
    '''这是一个创建数据库的方法'''
    #获得链接
    a={'host':'localhost','port':3306,'user':'root','password':'*******','charset':'utf8'}
    con = pymysql.connect(**a)
    #获得游标
    cur = con.cursor()
    #创建一个数据库 写出sql语言
    sql = "CREATE database music_db default character set='utf8'"
    #执行
    cur.execute(sql)
    #关闭游标
    cur.close()
    #关闭链接
    con.close()
#封装数据库,里面有对数据库建立连接关闭连接,sql_dml对数据增更新删除方法,和see_sql查询方法,单条数据叫做see_one
class Dbutil:
    '''这是一个封装mysql的一个工具类
    实现了链接,获取游标,关闭游标,关闭链接
    对数据添加,更新,删除的操作
    对数据的查询操作
    '''
    #第一步,数据库的信息,放在类属性里面
    mysql_shuju={
        'host':'localhost',
        'port':3306,
        'user':'****',
        'password':'********',
        'db':'music_db',
        'charset':'utf8'
    }
    def __init__(self):
        '''初始化里面,创建链接'''
        #获得大哥,创建链接
        self.con=pymysql.connect(**Dbutil.mysql_shuju)  #字典类型的传入方式
        #获得小弟,获得游标
        self.cur=self.con.cursor()

    def close_data(self):
        '''这个是关闭游标,关闭链接'''
        if self.cur: #判断里面时候有值
            self.cur.close()
        if self.con:
            self.con.close()
    def sql_dml(self,sql,args):
        '''这封装了对数据库的数据做增,更,删除等操作'''
        try:
            #执行sql语句,并把参数传递进去
            self.cur.execute(sql,args)
        except BaseException as e:
            print('数据执行失败,原因:',e)
            if self.con:
                self.con.rollback()  #回滚操作
        else:
            self.con.commit()  #如果没错错误,执行sql语句
        finally:
            self.close_data() #依次关闭游标和关闭链接
    def sql_dml1(self,sql,args):
        '''这封装了对数据库的数据做增,更,删除等操作'''
        try:
            #执行sql语句,并把参数传递进去
            self.cur.execute(sql,args)
            #获取
            id=self.con.insert_id()
        except BaseException as e:
            print('数据执行失败,原因:',e)
            if self.con:
                self.con.rollback()  #回滚操作
        else:
            self.con.commit()  #如果没错错误,执行sql语句
            #返回id
            return id
        finally:
            self.close_data() #依次关闭游标和关闭链接
    def see_sql(self,sql,args):
        '''这是一个查询的操作'''
        try:
            self.cur.execute(sql,args)
            return self.cur.fetchall()
        except BaseException as e:
            print('程序执行失败,原因:',e)
        finally:
            self.close_data()  #关闭数据
    def see_one(self,sql,args):
        '''这是一个查询返回单挑数据的操作'''
        try:
            self.cur.execute(sql,args)
            return self.cur.fetchone()
        except BaseException as e:
            print('程序执行失败,原因:',e)
        finally:
            self.close_data()  #关闭数据
#这个是创建用户表的方法
def create_t_user():
    '''创建用户表'''
    #创建用户表 调用sql——dml方法
    #用户表有 id uname pwd
    sql='''
    create table t_user(
    id int primary key auto_increment,
    uname varchar(32),
    pwd varchar(32)
    )
    '''
    Dbutil().sql_dml(sql,args=())
#这是一个新增用户的方法:
#这个是创建音乐表的方法
def create_t_music():
    '''这是一个歌曲列表'''
    #分析:歌曲表 需要有id  需要有歌曲名称,歌曲作者,歌曲地址
    sql='''
    create table t_music(
    id int primary key auto_increment,
    mname varchar(64),
    zuozhe varchar(64),
    tpath  varchar(512)
    )
    '''
    Dbutil().sql_dml(sql,args=())
#这个是创建用户的音乐列表的方法,也就是播放列表
def create_play_list():
    '''这是一个音乐播放列表'''
    #分析,列 有id  有用户id 和用户表的id关联  有mid 和音乐列表的id关联
    sql='''
    create table play_list(
    id int primary key auto_increment,
    u_id int,
    m_id int,
    foreign key (u_id) references t_user(id),
    foreign key (m_id) references t_music(id)
    )
    '''
    Dbutil().sql_dml(sql,args=())
#创建了2个用户
def create_user():
    '''这个函数是创建用户的方法'''
    sql='''
    insert into t_user values(0,'wwww','123456')
    '''
    Dbutil().sql_dml(sql,args=())
    sql1='''
    insert into t_user values(0,'wwww1','123456')
    '''
    Dbutil().sql_dml(sql1,args=())
#编写一个音乐服务类 后台和数据库交互
class MusicService:
    def __init__(self):
        self.user=None
    def login(self,uname:str,pwd:str)->bool:
        '''
        登录功能
        :param uname: 用户名
        :param pwd: 密码
        :return: 登录成功返回True,失败返回False
        '''
        #编写sql
        sql= 'select id,uname from t_user where uname=%s and pwd=%s'
        #查询         id和用户名   来自 用户表  条件 用户名的值  和密码的值
        args=(uname,pwd)
        user=Dbutil().see_one(sql,args)  #返回单条数据
        print(Dbutil().see_one(sql,args))
        if user:
            print('登录成功')
            #记录下用户信息
            self.user=user
            print('用户信息:',user)
            print('看看时候有值',self.user[0])
            return True
        else:
            print('登录失败')
            return False
    #导入音乐
    def add_muisc(self,fifes:tuple[str])->None:
        '''
        这是一个导入音乐的方法
        :param fifes: 音乐路径,默认是多个,里面的元素是字符串
        :return: None
        '''
        #编写sql语句 ,准备对我们音乐表格做数据添加
        sql='''
        insert into t_music(mname,tpath) values(%s,%s)
        '''
        for i in fifes:
            # ('D:/PycharmProjects/mypro01/课程笔记/2,项目-开发音乐盒/不醉不会.mp3',)
            # 导入音乐
            # ('D:/PycharmProjects/mypro01/课程笔记/2,项目-开发音乐盒/Maria - 极乐净土.ogg',)
            # D: / PycharmProjects / mypro01 / 课程笔记 / 项目 - 开发音乐盒 / Maria - 极乐净土.ogg
            # 导入音乐
            # ('D:/PycharmProjects/mypro01/课程笔记/2,项目-开发音乐盒/人间烟火.mp3',)
            print(i)
            a=i[i.rfind('/')+1:i.rfind('.')]
            print(a)#从后面往前找,找到斜杠+1和.之间的数值
            print(type(a))  # 从后面往前找,找到斜杠+1和.之间的数值
            #执行sql
            args=(a,i)  #元组类型 添加到表格里面去
            mid=Dbutil().sql_dml1(sql,args)  #执行数据库添加数据的方法 传入数据添加到音乐表格中

            #用户和音乐列表之间的关系
            #sql语言
            sql1='''
            insert into play_list(u_id,m_id) values(%s,%s)
            '''
            #执行sql语言  #u_id 等于我们用户名信息下的第一个值
            print('用户的id',self.user[0])
            #self.user这个值是我么通过在登录的时候,拿到的这个值,然后因为我们在一个类,所以能拿到
            #mid是我们通过外面的一个变量,也就是MusicService()的一个实例对象,来帮我们传递的值。我们始终调用这个实例对象
            #所以他
            args=(self.user[0],mid)
            Dbutil().sql_dml(sql1,args)
    def find_daoru(self)->list[str]:
        '''这是一个导入播放列表的后端查询'''
        sql='''
        select t.mname from play_list p,t_music t where p.m_id=t.id and p.u_id=%s
        '''
        args=(self.user[0],)
        #通过执行这个可以拿到播放列表
        m_list=Dbutil().see_sql(sql,args)
        #返回结果
        return m_list
    def bofang_miusc(self,mname:str):
        '''点击播放按钮后,的后端操作'''
        #编写查找地址的sql语言
        sql='''
        select t.tpath from t_music t,play_list p where t.id=p.m_id and p.u_id=%s and t.mname=%s
        '''
        #把地址通过数据库的单挑查询函数,查询出来
        args=(self.user[0],mname)
        path=Dbutil().see_one(sql,args)
        #地址是一个元组类型,我们需要把查找下标索引值获得正确的地址
        print('测试ixai这个是',path[0])
        pygame.mixer.init()  # 初始化所有引入的模块
        pygame.mixer.music.load(path[0])  # 载入音乐,音乐可以是 ogg、mp3 等格式
        pygame.mixer.music.play()  # 播放载入的音乐

    def bofang_miusc1(self,mname:str):
        '''点击播放按钮后,的后端操作'''
        #编写查找地址的sql语言
        sql='''
        select t.tpath from t_music t,play_list p where t.id=p.m_id and p.u_id=%s and t.mname=%s
        '''
        #把地址通过数据库的单挑查询函数,查询出来
        args=(self.user[0],mname)
        path=Dbutil().see_one(sql,args)
        #地址是一个元组类型,我们需要把查找下标索引值获得正确的地址
        print('lalal',path[0])
        pygame.mixer.init()  # 初始化所有引入的模块
        pygame.mixer.music.load(path[0])  # 载入音乐,音乐可以是 ogg、mp3 等格式
        pygame.mixer.music.play()  # 播放载入的音乐
        audio = MP3(path[0])
        time.sleep(int(audio.info.length))








    def delect_miuxs(self,mname):
        #删除音乐
        #第一步找到要删除音乐的id  通过用户名和歌曲名字
        sql11='''
        select t.id from t_music t,play_list p where t.id=p.m_id  and p.u_id=%s and t.mname=%s
        '''
        args1=(self.user[0],mname)
        mid=Dbutil().see_one(sql11,args1)
        print(mid,mid[0])

        #根据歌曲id 和用户id  删除播放列表12
        sql12='''
        DELETE from play_list where play_list.m_id=%s and play_list.u_id=%s;
        '''
        args=(mid[0],self.user[0])
        Dbutil().sql_dml(sql12,args)  #执行删除这个play_list表格的数据
        #根据歌曲id删除歌曲表的歌曲信息
        sql13='''
        DELETE from t_music where id=%s
        '''
        args2=(mid[0],)
        Dbutil().sql_dml(sql13,args2)
#这里面都是后端代码服务和逻辑
# **************************************************

#创造一个播放器的ui界面  16,前端-html
class Play_window:

    def __init__(self):
        self.top = tkinter.Tk()  # 获取主窗口 #第一步获取主窗口
        # shijian1 = time.strftime('%Y.%m.%d %H:%M:%S', time.localtime(time.time()))
        self.top.title('凡梦音乐播放器')  # 第2步,给窗口取一个名字
        self.top.focus_force()  # 新窗口获得焦点
        # 第3步,设定窗口的大小(长 * 宽)
        self.top.geometry('1000x600')
        # 设定背景颜色
        self.top.configure(bg='gray')
        #设置对话框大小不可改变
        self.top.resizable(width=False, height=False)
        #设置图片背景
        #---------------------
        def get_img(filename, width, height):
            im = Image.open(filename).resize((width, height))
            im = ImageTk.PhotoImage(im)
            return im
        self.canvas_root = tk.Canvas(self.top, width=1000, height=600)
        im_root = get_img('133.jpg', 1200, 1100)
        self.canvas_root.create_image(410, 200,image=im_root)
        self.canvas_root.pack()
        #-----------------------
        # 按钮图片导入方法
        # img_open = imim.open("背景.png")
        # img_png = ImageTk.PhotoImage(img_open)
        # # ppm_button = Button(root, image=img_png)
        #这里是设置按钮的参数
        # an1 = tkinter.Button(self.top1, relief=tkinter.GROOVE, activebackground='pink', activeforeground='red',
        #                      image=img_png,
        #                      fg='purple', bg='orange', text='播    放12', width=100, height=20, font=('宋体', 50),
        #                      command=None)
        # an1.place(x=10, y=10, anchor='nw')
        # cursor = "xterm"  是书写 arrow箭头 watch 转圈
        # image = photo, text = compound[i], compound = compound[i]

        #按钮全部重写                     #框架样式               点击之后按钮是粉色的              点击之后字体是红色的
        an1 = tkinter.Button(self.top,relief=tkinter.GROOVE,activebackground = 'pink', activeforeground = 'red',
                             fg='purple', bg='pink',text='播放音乐',
                             width=8, height=2,font=('宋体', 15,'bold'), command=self.bofang)
                            #字体颜色      bg:按钮的背景色    字体内容 大小 加粗      按钮的宽度   按钮的高度    字体的大小      响应的函数
        an1.place(x=10, y=10, anchor='nw')
        an2 = tkinter.Button(self.top,relief=tkinter.GROOVE,activebackground = 'pink', activeforeground = 'red',
                             fg='purple', bg='pink',text='导入音乐',
                             width=8, height=2,font=('宋体', 15,'bold'),command=self.daoru)
        an2.place(x=120, y=10, anchor='nw')
        an3 = tkinter.Button(self.top,relief=tkinter.GROOVE,activebackground = 'pink', activeforeground = 'red',
                             fg='purple', bg='pink',text='删除音乐',
                             width=8, height=2,font=('宋体', 15,'bold'),command=self.shanchu)
        an3.place(x=230, y=10, anchor='nw')
        an4 = tkinter.Button(self.top,relief=tkinter.GROOVE,activebackground = 'pink', activeforeground = 'red',
                             fg='purple', bg='pink',text='返回登录',
                             width=8, height=2,font=('宋体', 15,'bold'),command=self.bangzhu)
        an4.place(x=340, y=10, anchor='nw')
        an5 = tkinter.Button(self.top,relief=tkinter.GROOVE,activebackground = 'pink', activeforeground = 'red',
                             fg='purple', bg='pink',text='暂停播放',
                             width=8, height=2,font=('宋体', 15,'bold'), command=self.zhantin)
        an5.place(x=800, y=10, anchor='nw')
        an6 = tkinter.Button(self.top,relief=tkinter.GROOVE,activebackground = 'pink', activeforeground = 'red',
                             fg='purple', bg='pink',text='继续播放',
                             width=8, height=2,font=('宋体', 15,'bold'),  command=self.bofang1)
        an6.place(x=800, y=110, anchor='nw')
        an7 = tkinter.Button(self.top,relief=tkinter.GROOVE,activebackground = 'pink', activeforeground = 'red',
                             fg='purple', bg='pink',text='增加音量',
                             width=8, height=2,font=('宋体', 15,'bold'),  command=self.jia)
        an7.place(x=800, y=210, anchor='nw')
        an8 = tkinter.Button(self.top,relief=tkinter.GROOVE,activebackground = 'pink', activeforeground = 'red',
                             fg='purple', bg='pink',text='降低音量',
                             width=8, height=2,font=('宋体', 15,'bold'),  command=self.jian)
        an8.place(x=800, y=310, anchor='nw')
        an9 = tkinter.Button(self.top,relief=tkinter.GROOVE,activebackground = 'pink', activeforeground = 'red',
                             fg='purple', bg='pink',text='下 一 曲',
                             width=8, height=2,font=('宋体', 15,'bold'),  command=self.xiayiqu)
        an9.place(x=800, y=410, anchor='nw')
        an10 = tkinter.Button(self.top,relief=tkinter.GROOVE,activebackground = 'pink', activeforeground = 'red',
                             fg='purple', bg='pink',text='上 一 曲',
                             width=8, height=2,font=('宋体', 15,'bold'),  command=self.shangyiqu)
        an10.place(x=800, y=510, anchor='nw')
        an11 = tkinter.Button(self.top,relief=tkinter.GROOVE,activebackground = 'pink', activeforeground = 'red',
                             fg='purple', bg='gold',text='随机播放',
                             width=8, height=2,font=('宋体', 10,'bold'), command=self.suijiboafang)
        an11.place(x=620, y=380, anchor='nw')
        an12 = tkinter.Button(self.top,relief=tkinter.GROOVE,activebackground = 'pink', activeforeground = 'red',
                             fg='purple', bg='gold',text='顺序播放',
                             width=8, height=2,font=('宋体', 10,'bold'),command=self.shunxubofang)
        an12.place(x=620, y=500, anchor='nw')
        an13 = tkinter.Button(self.top,relief=tkinter.GROOVE,activebackground = 'pink', activeforeground = 'red',
                             fg='purple', bg='gold',text='单曲循环',
                             width=8, height=2,font=('宋体', 10,'bold'), command=self.danqubofang)
        an13.place(x=450, y=310, anchor='nw')
        an14 = tkinter.Button(self.top,relief=tkinter.GROOVE,activebackground = 'pink', activeforeground = 'red',
                             fg='purple', bg='gold',text='顺序关闭',
                             width=8, height=2,font=('宋体', 10,'bold'), command=self.guanbi)
        an14.place(x=620, y=540, anchor='nw')
        an15 = tkinter.Button(self.top,relief=tkinter.GROOVE,activebackground = 'pink', activeforeground = 'red',
                             fg='purple', bg='gold',text='随机关闭',
                             width=8, height=2,font=('宋体', 10,'bold'),command=self.guanbi1)
        an15.place(x=620, y=420, anchor='nw')


        # 增加播放列表的对话框
        self.listbox = tkinter.Listbox(self.top, bg='pink', font=("宋体", 20,'bold'), width=28,height=10)
        self.listbox.place(x=5, y=80, anchor='nw')

        ### 第7步,创建并放置一个多行文本框text用以显示
        self.t = tkinter.Text(self.top, bg='pink',font=('草体', 20,'bold'), width=40, height=10)
        self.t.place(x=5, y=380,anchor='nw')
        var='''您好,欢迎来到【凡梦播放器】,
        
新用户-->点击【导入音乐】,点击【播放】开始播放音乐;

老用户-->点击列表里面的音乐,点击【播放】开始播放音乐。
        '''
        self.t.insert('insert', var)

        #显示播放当前用户的播放列表
        self.jiza()

        #这里是设置的变量,每次调用都会增加的变量
        #这个是音乐的音量
        self.yinliang=0.7
        #这里是控制音乐列表的
        self.index=None
        self.shunxu=False
        self.t1=None
        self.t2 = None


        self.top.mainloop()  # 主窗口循环展示 #第二步主窗口循环展示



    def guanbi(self):
        #关闭进程
        self.t.delete(1.0, 'end')  # 清空显示对话框
        stop_thread(self.t1)
        pygame.mixer.init()
        pygame.mixer.music.pause()
        print("线程都被杀死了")
        var = \
f'''您好,欢迎实用【凡梦音乐播放器】,这是【凡梦】学习python以来第二个用来练手的软件。
你刚才中止 顺序循环播放 
当前状态下,结束循环,下次开启请在点击歌曲播放'''
        # 通过传递过来的这个值,去查找名字 完成播放
        self.t.insert('insert', var)
    def guanbi1(self):
        # 关闭进程
        self.t.delete(1.0, 'end')  # 清空显示对话框
        stop_thread(self.t2)
        pygame.mixer.init()
        pygame.mixer.music.pause()
        print("线程都被杀死了")
        var = \
f'''您好,欢迎实用【凡梦音乐播放器】,这是【凡梦】学习python以来第二个用来练手的软件。
你刚才中止 随机循环播放 
当前状态下,结束循环,下次开启请在点击歌曲播放
---
'''
        # 通过传递过来的这个值,去查找名字 完成播放
        self.t.insert('insert', var)



    def danqubofang(self):      #Play_window().danqubofang(self)
        print('您点击了单曲播放')
        self.t.delete(1.0, 'end')  # 清空显示对话框
        # 编写查找地址的sql语言
        us=ms.user[0]
        # 获取当前列表中选中的音乐
        self.index = int(self.listbox.curselection()[0])
        mnane=self.listbox.get(self.index)
        print(self.index,type(self.index),type(mnane),mnane,111111)
        # print('这是在歌曲中查看歌曲的名字',mnane)
        # ms.bofang_miusc(mnane)
        sql = '''
         select t.tpath from t_music t,play_list p where t.id=p.m_id and p.u_id=%s and t.mname=%s
         '''
        # 把地址通过数据库的单挑查询函数,查询出来
        args=(us,mnane)
        path = Dbutil().see_one(sql, args)
        print(path[0])
        # 地址是一个元组类型,我们需要把查找下标索引值获得正确的地址
        audio = MP3(path[0])
        pygame.mixer.init()  # 初始化所有引入的模块
        pygame.mixer.music.load(path[0])  # 载入音乐,音乐可以是 ogg、mp3 等格式
        pygame.mixer.music.play(-1)  # 播放载入的音乐  #循环播放
        var = \
    f'''您好,欢迎实用【凡梦音乐播放器】,这是【凡梦】学习python以来第二个用来练手的软件。
你刚刚点击了【单曲播放】
你当前播放的歌曲中名字是:【{mnane}】
位于播放列表中第:【{self.index + 1}】首歌
【{mnane}】单曲循环中……

'''
        # 通过传递过来的这个值,去查找名字 完成播放
        self.t.insert('insert', var)
    def shunxubofang(self):
        print('您点击了顺序播放')
        #当歌曲播放完毕之后,自动切歌:
        # 开辟线程  #                                   #设置一下,当主进程关闭,子线程自动关闭

        self.t1=threading.Thread(target=self.zidong1,daemon=True)
        self.t1.start() #开启线程
    def zidong1(self):
        print('看看子线程有无开启')
        m_list = ms.find_daoru()
        while 1:
            for i in m_list:
                print(i[0])  #i【0】  是歌曲的名字
                #这个是歌曲的播放时间
                #找到当前歌曲的播放时间
                #通过歌曲名字找到歌曲播放的地址
                sql = '''
                select t.tpath from t_music t,play_list p where t.id=p.m_id and t.mname=%s
                '''
                # 把地址通过数据库的单挑查询函数,查询出来
                args = (i[0],)
                path = Dbutil().see_one(sql, args)
                #通过歌曲名字,拿到歌曲的播放地址
                audio = MP3(path[0])  #n是播放地址
                print('当前歌曲的地址是:',path[0])
                print('当前歌曲的播放时长是;',int(audio.info.length))
                #通过歌曲的播放地址,获取到歌曲的播放时长
                # #循环播放当前列表的歌曲
                ms.bofang_miusc(i[0])
                print('当前播放的歌曲是:',i[0])
                #每首歌曲依次播放,然后等待歌曲播放完毕,进入下一个首播放
                self.t.delete(1.0, 'end')  # 清空显示对话框
                var = \
    f'''您好,欢迎实用【凡梦音乐播放器】,这是【凡梦】学习python以来第二个用来练手的软件。
    现在是列表循环播放,当前播放的歌曲是:【{i[0]}】
    
    
'''
                self.t.insert('insert', var)

                time.sleep(int(audio.info.length))

    def suijiboafang(self):
        print('您点击了随机播放')
        self.t2=threading.Thread(target=self.zidong2,daemon=True)
        self.t2.start() #开启线程
    def zidong2(self):
        print('自动播放的线程开启')
        #等待这个歌曲播放完毕,然后自动切换到下一曲
        self.t.delete(1.0, 'end')  # 清空显示对话框
        var = \
    f'''您好,欢迎实用【凡梦音乐播放器】,这是【凡梦】学习python以来第二个用来练手的软件。
你刚刚点击了【随机播放】

'''
        self.t.insert('insert', var)

        while 1:
            #调用下面封装好的函数  死循环去实现吧 除非我们手动杀死这个子线程
            self.fen1()

    def fen1(self):
        # self.t.delete(1.0, 'end')  # 清空显示对话框
        m_list = ms.find_daoru()
        self.index = 0 + random.randint(0, (len(m_list)-1))
        print('当前歌曲的下标内部2', self.index)
        self.mnane = self.listbox.get(str(self.index))

        ms.bofang_miusc1(self.mnane)



    def xiayiqu(self):
            print('你点击了下一曲')
            self.t.delete(1.0, 'end')   #清空显示对话框
            #增加,每次点击一下增加一个索引值
            #找到播放列表
            m_list = ms.find_daoru()
            #找到播放列表的长度
            # print(m_list,type(len(m_list)),type(m_list))
            #当索引值小于长度-1的时候,就可以增加
            if self.index<(len(m_list)-1):
                #当前歌曲的索引小于列表长度减1的时候,就可以直接+1
                self.index=self.index+1
                print(self.index,11111)
                #根据索引找到名字
                self.mnane=self.listbox.get(str(self.index))
                # print('这是在歌曲中查看歌曲的名字', self.mnane, self.index)
                var=\
    f'''您好,欢迎实用【凡梦音乐播放器】,这是【凡梦】学习python以来第二个用来练手的软件。
    你刚刚点击了【下一曲】
    你当前播放的歌曲中名字是:【{self.mnane}】
    位于播放列表中第:【{self.index+1}】首歌
    
    
'''
                #通过传递过来的这个值,去查找名字 完成播放
                ms.bofang_miusc(self.mnane)
                self.t.insert('insert', var)
            else:
                self.index=0
                # print('这是在歌曲中查看歌曲的名字', self.mnane, self.index)
                var =\
    f'''您好,欢迎使用【凡梦音乐播放器】,这是凡梦学习python以来第二个用来练手的软件。
    你刚刚点击了【下一曲】
    你当前播放的歌曲中名字是: 【{self.mnane}】
    位于播放列表中第:【{self.index+1}】首歌
    
    
'''
                ms.bofang_miusc(self.mnane)
                self.t.insert('insert', var)



    def shangyiqu(self):
        print('你点击了上一曲')
        self.t.delete(1.0, 'end')  # 清空显示对话框
        #增加,每次点击一下减少一个索引值
        m_list = ms.find_daoru()
        if self.index>0:
            self.index=self.index-1
            print(self.index,11111)
            self.mnane=self.listbox.get(str(self.index))
            # print('这是在歌曲中查看歌曲的名字',self.mnane,self.index)
            var = \
f'''您好,欢迎实用【凡梦音乐播放器】,这是【凡梦】学习python以来第二个用来练手的软件。
你刚刚点击了【上一曲】
你当前播放的歌曲中名字是:【{self.mnane}】
位于播放列表中第:【{self.index+1}】首歌


'''
            ms.bofang_miusc(self.mnane)
            self.t.insert('insert', var)
        else:
            self.index=(len(m_list)-1)
            self.mnane=self.listbox.get(str(self.index))
            # print('这是在歌曲中查看歌曲的名字',self.mnane,self.index)
            var = \
f'''您好,欢迎实用【凡梦音乐播放器】,这是【凡梦】学习python以来第二个用来练手的软件。
你刚刚点击了【上一曲】
你当前播放的歌曲中名字是:【{self.mnane}】
位于播放列表中第:【{self.index+1}】首歌


'''
            ms.bofang_miusc(self.mnane)
            self.t.insert('insert', var)

    def bofang1(self):
        print('继续播放')
        self.t.delete(1.0, 'end')  # 清空显示对话框
        pygame.mixer.init()
        pygame.mixer.music.unpause()   #继续播放当前的音乐
        var = \
f'''您好,欢迎实用【凡梦音乐播放器】,这是【凡梦】学习python以来第二个用来练手的软件。
你刚刚点击了【继续播放】按钮,歌曲为您播放



'''
        self.t.insert('insert', var)
    def zhantin(self): #暂停播放
        print('暂停了音乐')
        self.t.delete(1.0, 'end')  # 清空显示对话框
        pygame.mixer.init()
        pygame.mixer.music.pause()   #暂停当前的音乐
        var = \
f'''您好,欢迎实用【凡梦音乐播放器】,这是【凡梦】学习python以来第二个用来练手的软件。
你刚刚点击了【暂停播放】按钮,歌曲开启暂停,点击【继续播放】按钮可继续播放



'''
        self.t.insert('insert', var)

    def jian(self):
        print('音量减少了一下')
        self.t.delete(1.0, 'end')  # 清空显示对话框
        pygame.mixer.init()
        self.yinliang = self.yinliang - 0.1
        if self.yinliang<0:
            self.yinliang=0
        pygame.mixer.music.set_volume(self.yinliang)  # 设置音量
        print('当前音量',self.yinliang)
        var = \
f'''您好,欢迎实用【凡梦音乐播放器】,这是【凡梦】学习python以来第二个用来练手的软件。
你刚刚点击了【降低音量】按钮,当前音量{self.yinliang:.1f}



'''
        self.t.insert('insert', var)

    def jia(self):
        print('音量增加了一下')
        self.t.delete(1.0, 'end')  # 清空显示对话框
        pygame.mixer.init()
        self.yinliang = self.yinliang +0.1
        if self.yinliang>2.5:
            self.yinliang=2.5
        pygame.mixer.music.set_volume(self.yinliang)  # 设置音量
        print('当前音量',self.yinliang)
        var = \
f'''您好,欢迎实用【凡梦音乐播放器】,这是【凡梦】学习python以来第二个用来练手的软件。
你刚刚点击了【增加音量】按钮,当前音量{self.yinliang:.1f}



'''
        self.t.insert('insert', var)  #浮点数的格式化 显示1位小数点
        #播放音乐的函数

    def bofang(self):
        print('播放音乐')
        self.t.delete(1.0, 'end')  # 清空显示对话框
        # 获取当前列表中选中的音乐
        self.index = int(self.listbox.curselection()[0])
        index=self.listbox.curselection()
        mnane=self.listbox.get(index)
        print(index,type(index),type(mnane),mnane,111111)
        # print('这是在歌曲中查看歌曲的名字',mnane)
        ms.bofang_miusc(mnane)
        var = \
f'''您好,欢迎实用【凡梦音乐播放器】,这是【凡梦】学习python以来第二个用来练手的软件。

你刚刚点击了【播放音乐】按钮,
当前播放的音乐【{mnane}】,位于歌曲列表第【{index[0]+1}】首

'''
        self.t.insert('insert', var)



    #导入音乐的函数 后端
    def daoru(self): #这是一个事件函数,必须传入参数event
        print('导入音乐')
        self.t.delete(1.0, 'end')  # 清空显示对话框
        #设置导入音乐的格式
        filenames=askopenfilenames(filetypes=[('mp3','.mp3'),('ogg','.ogg')])
        print(filenames)
        #调入后端我们创建列表的类
        ms.add_muisc(filenames)
        m_list = ms.find_daoru()
        # 打印出来看看长啥样
        # print(m_list)
        # 把这个列表显示在我们前端界面上 ,我们永远这是添加最后一首歌就完事儿了
        self.listbox.delete(0, tkinter.END)
        for i in m_list:
            self.listbox.insert(0, i[0])
        var = \
f'''您好,欢迎实用【凡梦音乐播放器】,这是【凡梦】学习python以来第二个用来练手的软件。
你刚刚点击了【导入音乐】按钮,
当前导入的音乐是【{m_list[-1][0]}】



'''
        self.t.insert('insert', var)
    def jiza(self):
        '''这个是加载播放列表'''
        #通过我们查询的代码 获得属于当前用户的音乐播放列表
        m_list=ms.find_daoru()
        #打印出来看看长啥样
        # print(m_list)
        self.listbox.delete(0,tkinter.END)
        for i in m_list:
        #显示的时候,需要显示全部列表的内容
            self.listbox.insert(0,i[0])

    def shanchu(self):
        print('删除音乐')
        self.t.delete(1.0, 'end')  # 清空显示对话框
        #获取当前列表中选中的音乐
        index=self.listbox.curselection()
        print(index) #显示的是当前播放列表中的下标索引值
        mnane=self.listbox.get(index)
        print(mnane,type(mnane),mnane[0],type(mnane[0]))

        #执行了删除之后,刷新一下列表,更新要显示的内容
        ms.delect_miuxs(mnane)
        self.jiza()
        #点击删除后,音乐暂停
        pygame.mixer.init()
        pygame.mixer.music.pause()   #暂停当前的音乐
        var = \
f'''您好,欢迎实用【凡梦音乐播放器】,这是【凡梦】学习python以来第二个用来练手的软件。
你刚刚点击了【删除音乐】按钮,
当前删除的音乐是【{mnane}】



'''
        self.t.insert('insert', var)
    #帮助一下的函数
    def bangzhu(self):
        # 设置tkinter框架的几何形状
        print('返回登录')
        a = tkinter.messagebox.askokcancel('提示', '是否返回登录界面 ')  # True和false提示框  确定和取消
        if a:
            #音乐初始化
            pygame.mixer.init()
            #停止播放音乐
            pygame.mixer.music.stop()
            #关闭当前窗口
            self.top.destroy()
            #进入登录界面
            return Denglu()


        # top1.destroy()  # 关闭当前窗口
        

#这个是杀死线程的工具
def _async_raise(tid, exctype):
    """raises the exception, performs cleanup if needed"""
    tid = ctypes.c_long(tid)
    if not inspect.isclass(exctype):
        exctype = type(exctype)
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
    if res == 0:
        raise ValueError("invalid thread id")
    elif res != 1:
        # """if it returns a number greater than one, you're in trouble,
        # and you should call it again with exc=NULL to revert the effect"""
        ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
        raise SystemError("PyThreadState_SetAsyncExc failed")

#杀死线程的工具
def stop_thread(thread):
    _async_raise(thread.ident, SystemExit)



#创造一个登录和注册的ui界面
class Denglu:
    def __init__(self):
        #获取窗口
        self.top1 = tkinter.Tk()  # 获取主窗口 #第一步获取主窗口
        self.top1.title('登录界面')  # 第2步,给窗口取一个名字
        self.top1.geometry('800x450')  # 设定窗口大小
        # 设定背景颜色
        self.top1.configure(bg='gray')
        #设置对话框大小不可改变
        self.top1.resizable(width=False, height=False)
        #设置图片为背景
        # 设置背景图片
        def get_img(filename, width, height):
            im = Image.open(filename).resize((width, height))
            im = ImageTk.PhotoImage(im)
            return im
        canvas_root = tk.Canvas(self.top1, width=1000, height=600)
        im_root = get_img('133.jpg', 1000, 600)
        canvas_root.create_image(500, 300, image=im_root)
        canvas_root.pack()
        #--------------------------------

        # 创建标签
        l1 = tkinter.Label(self.top1,bg='gold', text='请   输   入   用   户   名:', font=('Arial', 12), width=20, height=2)
        l1.place(x=70, y=80, anchor='nw')
        l2 = tkinter.Label(self.top1, bg='gold',text='请   输   入   密   码:', font=('Arial', 12), width=20, height=2)
        l2.place(x=70, y=140, anchor='nw')
        # 创建txt输入窗口
        self.e1 = tkinter.Entry(self.top1, bg='pink',show=None, font=('Arial', 26))
        self.e1.place(x=270, y=77, anchor='nw')
        self.e2 = tkinter.Entry(self.top1, bg='pink',show='*', font=('Arial', 26))  #不显示用户密码
        self.e2.place(x=270, y=137, anchor='nw')

        # 这里是设置登录按钮的
        b1 = tkinter.Button(self.top1, fg='purple', bg='orange',font=('宋体', 15), text='登    录', width=12, height=2, command=self.get1)
        b1.place(x=250, y=220, anchor='nw')
        b1 = tkinter.Button(self.top1, fg='purple', bg='orange',font=('宋体', 15),text='注     册', width=12, height=2, command=self.get2)
        b1.place(x=490, y=220, anchor='nw')




        # 这是设置下方txt对话框提示的
        self.t = tkinter.Text(self.top1, bg='pink', font=('草体', 20), width=40, height=5)
        self.t.place(x=100, y=300, anchor='nw')
        var = '''您好,欢迎来到【凡梦播放器】

新用户——>输入用户名和密码,点击【注册】

老用户——>输入用户名和密码,点击【登录】
                '''
        self.t.insert('insert', var)

        self.top1.mainloop()  # 主窗口循环展示 #第二步主窗口循环展示
        # 这个函数是验证按钮的函数
    def get1(self):
        #新增一个对话框
        a = tkinter.messagebox.askokcancel('提示', '是否登录 ')  # True和false提示框  确定和取消
        if a:
            self.t.delete(1.0, 'end')
            uname = self.e1.get()
            pwd = self.e2.get()
            if ms.login(uname, pwd):  # 判定用户名和密码时候登录成功
                # print('1')
                var = f'登录成功,欢迎{uname}进入我们的播放器'
                self.t.insert('insert', var)
                self.e1.delete(0, 'end')
                self.e2.delete(0, 'end')
                self.top1.destroy() #关闭当前窗口
                Play_window()  #进入播放器ui界面
            else:
                var = f'登录失败,请输入正确的用户名和密码'
                self.t.insert('insert', var)
                self.e1.delete(0, 'end')
                self.e2.delete(0, 'end')
    def jiance(self,a):
        sql='''
        SELECT uname from t_user where uname in(%s)
        '''
        args=(a,)
        t1=Dbutil().see_sql(sql,args)
        if t1:
            return True
        else:
            return False
    def get2(self):
        #注册
        #新增一个对话框
        a = tkinter.messagebox.askokcancel('提示', '是否注册 ')  # True和false提示框  确定和取消
        if a:
            self.t.delete(1.0, 'end')
            uname1 = self.e1.get()
            pwd1 = self.e2.get()
            if self.jiance(uname1):
                var = f'注册失败,用户名已经存在;'
                self.t.insert('insert', var)
                self.e1.delete(0, 'end')
                self.e2.delete(0, 'end')
            elif len(uname1) > 3 and len(pwd1) > 3 :
                sql = '''insert into t_user values(0,%s,%s,%s)
                           '''
                shijian1 = time.strftime('%Y.%m.%d %H:%M:%S', time.localtime(time.time()))
                s1 = shijian1.replace('.', '-')
                args = (uname1, pwd1, s1)
                # 把数据添加到数据表里面去
                Dbutil().sql_dml(sql, args)
                var = f'注册成功,请记住你的用户名和密码,你注册的用户名是【{uname1}】'
                self.t.insert('insert', var)
                self.e1.delete(0, 'end')
                self.e2.delete(0, 'end')
                    # 数据库增加数据的语句
            else:
                var = f'注册失败,请输入正确的用户名和密码'
                self.t.insert('insert', var)
                self.e1.delete(0, 'end')
                self.e2.delete(0, 'end')













if __name__ == '__main__':
    #这是后端逻辑,和数据库的交互
    ##############################################################
    #这里面的代码都是实现了后台的逻辑,和数据库的交互
    #调用创建数据库的方法,实现创建
    # create_database()  #创建成功之后,我们注释掉
    #创建用户表
    # create_t_user()  #创建成功之后,我们注释掉
    #创建音乐列表
    # create_t_music() #创建成功之后,我们注释掉
    #创建播放列表
    # create_play_list()  #创建成功之后,我们注释掉
    #创建用户,一口气创建2个用户
    # create_user()  #创建成功之后,我们注释掉
    #测试时候能登录成功
    MusicService().login('wwww','123456')
    ############################################################
    #先创建一个变量 ,这个变量是作为一个媒介去传递各种值的
    ms = MusicService()
    Denglu()

运行本地音乐盒需要预先准备的环境

测试以上代码

1,需要安装python环境,以及该代码用到的库

2,需要安装Mysql数据库,并且按照代码注释的顺序,建立本地数据库,和建立几个用来存储数据的表格。

3,代码对连接数据库的账号和密码做了处理,请自行修改

4,歌曲自行准备,本音乐盒支持mp3和ogg格式,也可以修改里面导入音乐的类型的代码,以支持更多格式。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值