Python3_pygame—简易的音乐播放器
在pygame的学习中,接触到了其中的mixer.music模块,突发想法,就写了这个音乐播放器,可能时间不是太多,就只做了基础的部分。
本播放器使用了python中内置的模块:
pygame(pygame.mixer.music, pygame.event, pygame.time, pygame.display, pygame.draw.rect)
pickle(pickle.dump, pickle.load)
os(os.path.exists)
tkinter(tkinter.filedialog.askopenfilename, tkinter.messagebox,tkinter.Tk)
sys(sys.exit)
整个播放器的核心为pygame.mixer.music模块,以文件操作、pickle和os为辅完成音乐的载入和播放,用pygame.display建立窗口框架和窗口小组件,结合tkinter.Tk等建立二级小窗口协作完成整个程序。
本程序分为如下两大类和一个主函数:
- 文件类
文件类主要负责完成音乐载入、播放、添加等操作。
定义函数:
def __init__(self):
self.flag = False //音乐是否停止(可以去掉,因为音乐停止后获取音乐播放进度还是不变)
self.number = 0 //记录当前播放音乐的序号
self.all = 0 //音乐的总个数
self.length = 0 //当前音乐的长度
self.current = 0 //当前音乐播放的进度
self.load_information() //载入音乐
载入音乐路径文件函数:
def load_information(self):
global music_list //声明:在程序前方已经有全局变量定义,此为音乐路径文件
global music_name //同上,此为音乐名称文件
if os.path.exists("music.txt") == 0: //检测音乐文件是否存在...
music_db = open("music.txt", "wb") //创建文件
music_nm = open("name.txt","wb")
music_list = ['徐梦圆 - China-X.ogg']
music_name = ['徐梦圆 - China-X']
pickle.dump(music_list, music_db) //将列表保存到文件中
pickle.dump(music_name, music_nm) //同上
self.all = len(music_list)
music_db.close()
music_nm.close()
else:
music_db = open("music.txt", "rb")
music_nm = open("name.txt","rb")
music_list = pickle.load(music_db) //读取文件
music_name = pickle.load(music_nm) //同上
self.all = len(music_list)
music_db.close()
music_nm.close()
对音乐文件内容的实时更新和保存函数:
def save_music(self):
music_db = open("music.txt","wb")
music_nm = open("name.txt", "wb")
pickle.dump(music_list, music_db)
pickle.dump(music_name, music_nm)
music_db.close()
music_nm.close()
从本地系统添加音乐的函数:
def add_music(self): //稍微有些复杂此函数
middle = []
name_ = []
root = tkinter.Tk() //创建父窗口
root.withdraw() //让父窗口隐藏
self.file_opt = options = {} //一些关于askopenfilenames的参数
options['defaultextension'] = ''
options['filetypes'] = [('ogg files', '.ogg'), ('wav files', '.wav'),('mp3 files','.mp3')]
options['initialdir'] = 'C:\'
options['initialfile'] = ''
options['parent'] = root //root为打开文件的父窗口
options['title'] = '添加音乐文件...'
path_ = tkinter.filedialog.askopenfilenames(**self.file_opt)
root.destroy() //消除父窗口
for each in path_: //从音乐路径中的筛选出音乐名称
each = list(each)
name = ''
flag = False
while True:
try:
mid = each.pop()
except:
break
if mid == '/':
name_.append(name[::-1])
break
if flag == True:
name = name + mid
if mid == '.':
flag = True
for each in path_: //载入音乐路径
for other in music_list:
ok = 0
if other == each:
ok == 1
if (ok == 0) & (path_ != ''):
music_list.append(each)
self.all = self.all + 1
for each in name_: //载入音乐名称
music_name.append(each)
self.save_music() //保存到文件中
加载音乐的函数:
def load_music(self):
item = music_list.pop(0)
pygame.mixer.music.load(item.encode())
pygame.mixer.music.play()
self.length = pygame.mixer.Sound(item).get_length() //获取音乐的长度
music_list.insert(0, item) //借出去换回来
使音乐顺序且循环播放的函数:
def list_music(self):
if (self.number >= 0) & (self.all >= 0) & (self.number < self.all - 1): //用音乐个数做限制
self.number = self.number + 1
try:
pygame.mixer.music.load(music_list[self.number])
pygame.mixer.music.play()
self.length = pygame.mixer.Sound(music_list[self.number]).get_length()
except BaseException: //一般在路径不对或者音乐文件出错的情况下触发
root = tkinter.Tk()
root.withdraw()
tkinter.messagebox.showwarning(' ','The Music Is Error Or The Path Is Absence!!!') //弹出警告栏
music_list.remove(music_list[self.number]) //移除错误的音乐路径
self.all = self.all - 1
self.back_music()
root.destroy()
使前进一首的函数:
def advance_music(self):
try:
if self.number < self.all - 1: //对音乐的个数做判断
self.number = self.number + 1
pygame.mixer.music.stop()
pygame.mixer.music.load(music_list[self.number].encode())
pygame.mixer.music.play()
self.length = pygame.mixer.Sound(music_list[self.number]).get_length()
else:
root = tkinter.Tk()
root.withdraw()
messagebox.showwarning("提示", "已经是最后一首歌了...") //当all <= number时
root.destroy()
except BaseException: //同上面函数一样
root = tkinter.Tk()
root.withdraw()
tkinter.messagebox.showwarning(' ','The Music Is Error Or The Path Is Absence!!!')
music_list.remove(music_list[self.number])
music_name.remove(music_name[self.number])
self.save_music()
self.all = self.all - 1
self.back_music()
root.destroy()
使音乐后退一首的函数:
def back_music(self):
if self.number > 0:
self.number = self.number - 1
print(self.number)
pygame.mixer.music.stop() //停止当前音乐播放
pygame.mixer.music.load(music_list[self.number])
pygame.mixer.music.play()
self.length = pygame.mixer.Sound(music_list[self.number]).get_length()
else:
root = tkinter.Tk()
root.withdraw()
messagebox.showwarning('提示', "已经是第一首歌了...")
root.destroy()
音乐列表的展示的函数:
def display_music(self):
root = tkinter.Tk()
root.title("歌单")
root.resizable(False, False) //使root窗口不能改变大小
music = tkinter.Listbox(root, width=30) //tkinter的列表
music.pack() //放置listbox
for each in music_name:
music.insert(tkinter.END, each) //使音乐名称打印在列表窗口中
root.mainloop() //窗口循环
获取当前的音乐的实时播放时间的函数:
def get_current(self):
self.current = pygame.mixer.music.get_pos() / 1000 //除以1000是因为它是一毫秒为单位的,因此换算成秒。
- 组件类负责完成对各个窗口组件的设置和在主窗口的放置情况及功能。
定义函数:
def __init__(self,screen,img, pos_l, pos_t, volume = None):
self.screen = screen //主窗口
self.img = pygame.image.load(img).convert_alpha() //组件的图片
self.rect = self.img.get_rect() //组件的图片的坐标位置(建议先了解pygame)
self.rect.left, self.rect.top = pos_l, pos_t
self.flag = False
self.volume = volume //声音...
组件的放置函数:
def blit (self):
self.screen.blit(self.img,self.rect)
暂停按键功能函数:
def is_pause(self, other):
if self.flag == False: //判断是否按下暂停按键
self.blit()
if ~pygame.mixer.music.get_busy(): //判断音乐是否在播放
pygame.mixer.music.unpause() //继续播放
else:
self.screen.blit(other.img, other.rect)
pygame.mixer.music.pause() //暂停播放
def at_volume(self, other):
font = pygame.font.Font('simsun.ttf', 15) //设置音量字体
if self.flag == False: //判断是否按下音量键
self.blit()
else:
self.screen.blit(other.img, other.rect)
if (self.volume < 1) & (self.volume >= 0.1): //以100%和0%作为限制条件,进行增减音量
self.screen.blit(font.render(str(int(self.volume * 100)) + '%', True, (0, 0, 0)),
(self.rect.left + 10,self.rect.top + 14))
elif self.volume < 0.1:
self.screen.blit(font.render(str(int(self.volume * 100)) + '%', True, (0, 0, 0)),
(self.rect.left + 14,self.rect.top + 14))
else:
self.screen.blit(font.render(str(int(self.volume * 100)) + '%', True, (0, 0, 0)),
(self.rect.left + 5,self.rect.top + 14))
滑动球的放置函数:
def ball_blit(self, length, current, number):
font_1 = pygame.font.Font('simsun.ttf', 18) //设置播放时间和音乐名称的字体
font_2 = pygame.font.Font('simsun.ttf', 10)
black = (0, 0, 0)
lens = (current / length) * 150
self.screen.blit(font_1.render(music_name[number], True, black), (75, self.rect.top - 25)) //在窗口上写出音乐名称(字体居中待更新)
self.screen.blit(font_2.render(str(int(current)) + ' / ' + str(int(length)), True, black), (230, self.rect.top)) //在窗口上写出播放时间及总时长
pygame.draw.rect(self.screen, black, (75, 60, lens, 2)) //在窗口上画出播放条
self.rect.left, self.rect.top = 75 + lens - self.rect.width / 2, 61 - self.rect.width / 2
self.screen.blit(self.img, self.rect) //在对应位置画出滚动球
- 主函数
主函数由于比较长,所以分步骤给出代码…
- [窗口的建立与基本常量的设定]
def main()
size = width, height = 300, 200 //主窗口的大小
screen = pygame.display.set_mode(size) //主窗口建立
pygame.display.set_caption('music player') //窗口名称
pygame.init() //pygame初始化,下同...
pygame.mixer.init()
clock = pygame.time.Clock() //设置时间对象,便于设置窗口刷新的帧数
music_file = file_() //建立文件对象
flag = True //判断flag
music_file.load_music() //播放第一首
volume = 1 //音量
pygame.mixer.music.set_volume(volume)
icon = pygame.image.load('icon.png').convert_alpha() //窗口图标的载入和设置
pygame.display.set_icon(icon)
stand_width = 42 //标准宽度,方便后面的参数的设置,下同...
stand_left, stand_top =
width / 2 - stand_width / 2, 100
background = pygame.image.load(r"background.png").convert_alpha() //窗口背景的载入
process_bg = (200, 200, 200) //滚动条的颜色设置
- [组件的图标的载入和组件的初始化]
pause_img = 'pause.png' //载入图片
start_img = 'start.png'
sound_img = 'volume.png'
up_img = 'up.png'
down_img = 'down.png'
circle_img = 'circle.png'
music_img = 'music.png'
list_img = 'list.png'
advance_img = 'advance.png'
back_img = 'back.png'
ball_img = 'ball.png'
pause = mod(screen, pause_img, stand_left, stand_top) //组件初始化
start = mod(screen, start_img, stand_left, stand_top)
sound = mod(screen, sound_img, stand_left, start.rect.bottom + 5)
circle = mod(screen, circle_img, sound.rect.left, sound.rect.top)
up = mod(screen, up_img, sound.rect.left + stand_width + 5, sound.rect.top)
down = mod(screen, down_img, sound.rect.left - stand_width - 5, sound.rect.top)
music = mod(screen, music_img, down.rect.left - stand_width - 5, sound.rect.top)
List = mod(screen, list_img, up.rect.right + 5, sound.rect.top)
advance = mod(screen, advance_img, stand_left + stand_width + 5, stand_top)
back = mod(screen, back_img, stand_left - stand_width - 5, stand_top)
ball = mod(screen, ball_img, 0, 0)
- [while循环结构(实现窗口的整体刷新和所有功能***)]
while True:
screen.blit(background,(0, 0)) //主窗口背景的显示
pygame.draw.rect(screen, process_bg, (75, 60, 150, 2)) //总进度条的显示
ball.ball_blit(music_file.length, music_file.current, music_file.number) //滚动球的显示
if flag == True: //其余组件的显示(通过flag来决定是否显示<单击不是组件的部分flag改变,组件消失或显示>)
music.blit()
up.blit()
down.blit()
List.blit()
advance.blit()
back.blit()
pause.is_pause(start)
sound.at_volume(circle)
if music_file.flag == False: //判断并得到音乐当前播放的时间
pygame.display.flip() //屏幕的刷新(主要用于滚动球位置的刷新)
music_file.get_current()
if music_file.current >= music_file.length: //判断音乐是否结束
music_file.list_music() //结束,则开始下一首...
for event in pygame.event.get(): //pygame事件的获取...
if event.type == pygame.QUIT: //退出事件
pygame.quit() //pygame的退出
sys.exit() //程序的退出
if event.type == pygame.MOUSEBUTTONDOWN: //鼠标点击事件
if event.button == 1: //鼠标右键点击事件
if flag == True: //各个组件的点击区域及点击后发生的事件
if (pygame.mouse.get_pos()[0] >= pause.rect.left) & (pygame.mouse.get_pos()[0] <= pause.rect.right) &
(pygame.mouse.get_pos()[1] >= pause.rect.top) & (pygame.mouse.get_pos()[1] <= pause.rect.bottom):
pause.flag = ~pause.flag //暂停flag的设置
elif (pygame.mouse.get_pos()[0] >= sound.rect.left) & (pygame.mouse.get_pos()[0] <= sound.rect.right) &
(pygame.mouse.get_pos()[1] >= sound.rect.top) & (pygame.mouse.get_pos()[1] <= sound.rect.bottom):
sound.flag = ~sound.flag //音量查看的flag设置
elif (pygame.mouse.get_pos()[0] >= music.rect.left) & (pygame.mouse.get_pos()[0] <= music.rect.right) &
(pygame.mouse.get_pos()[1] >= music.rect.top) & (pygame.mouse.get_pos()[1] <= sound.rect.bottom):
music_file.add_music() //添加音乐
elif (pygame.mouse.get_pos()[0] >= up.rect.left) & (pygame.mouse.get_pos()[0] <= up.rect.right) &
(pygame.mouse.get_pos()[1] >= up.rect.top) & (pygame.mouse.get_pos()[1] <= up.rect.bottom): //音量的增减事件(下面三个都是一样)
if volume < 1:
volume = volume + 0.01
elif (pygame.mouse.get_pos()[0] >= down.rect.left) & (pygame.mouse.get_pos()[0] <= down.rect.right) &
(pygame.mouse.get_pos()[1] >= down.rect.top) & (pygame.mouse.get_pos()[1] <= down.rect.bottom):
if volume > 0:
volume = volume - 0.01
elif (pygame.mouse.get_pos()[0] >= advance.rect.left) & (pygame.mouse.get_pos()[0] <= advance.rect.right) &
(pygame.mouse.get_pos()[1] >= advance.rect.top) & (pygame.mouse.get_pos()[1] <= advance.rect.bottom):
music_file.advance_music() //播放下一首音乐
elif (pygame.mouse.get_pos()[0] >= back.rect.left) & (pygame.mouse.get_pos()[0] <= back.rect.right) &
(pygame.mouse.get_pos()[1] >= back.rect.top) & (pygame.mouse.get_pos()[1] <= back.rect.bottom):
music_file.back_music() //播放前一首音乐
elif (pygame.mouse.get_pos()[0] >= List.rect.left) & (pygame.mouse.get_pos()[0] <= List.rect.right) &
(pygame.mouse.get_pos()[1] >= List.rect.top) & (pygame.mouse.get_pos()[1] <= List.rect.bottom):
music_file.display_music() //显示音乐列表
else:
flag = ~flag //组件显示的flag
else:
flag = ~flag //组件显示的flag
pygame.mixer.music.set_volume(volume) //音量的刷新
sound.volume = volume //同上
pygame.display.flip() //整个窗口的刷新
clock.tick(20) //帧数的设置
- [最后的主程序]
if __name__ == "__main__":
main()
程序的.py文件和资源包链接:
[ 提取码:taac (https://pan.baidu.com/s/1n415BuA7T2WAMBzumjfrPQ) ]
盛年不重来,一日难再晨,及时当勉励,岁月不待人。————陶渊明