Pygame(二十)音乐播放器2
接上节内容:
# /usr/bin/python3
# Author: 爱编程的章老师
# @Time: 2021/1/17 0017
# E-mail: Bluesand2010@163.com
import pygame
import sys
import os
from random import randint
'''音乐播放器'''
# 音乐播放/暂停/继续/停止功能
# 实现播放列表显示功能
# 实现单曲循环/列表循环/随机播放功能
# 实现进度条拖动改变进度功能
# 实现音量调节
# 常量申明部分
WINDOW_SIZE = WINDOW_WIDTH, WINDOW_HEIGHT = 500, 300 # 窗体的大小设置
PATH_ROOT = os.path.split(sys.argv[0])[0]
PLAY_IMG_PATH = "/".join([PATH_ROOT, "src/img/play.png"]) # 播放按钮图片路径
PAUSE_IMG_PATH = "/".join([PATH_ROOT, "src/img/pause.png"]) # 暂停播放按钮图片路径
LOOP_IMG_PATH = "/".join([PATH_ROOT, "src/img/lOOP.png"]) # 循环播放按钮图片路径
SINGLE_LOOP_IMG_PATH = "/".join([PATH_ROOT, "src/img/loop1.png"]) # 循环播放按钮图片路径
STOP_IMG_PATH = "/".join([PATH_ROOT, "src/img/stop.png"]) # 停止播放按钮图片路径
NEXT_IMG_PATH = "/".join([PATH_ROOT, "src/img/next.png"]) # 后一曲与前一按钮图片路径
RANDOM_IMG_PATH = "/".join([PATH_ROOT, "src/img/random.png"]) # 随机播放钮图片路径
BUTTON_BAR_HEIGHT = 60 # 按钮条的高度
PROGRESS_BAR_HEIGHT = 30 # 进度条的高度
BUTTON_SIZE = 58 # 按钮的大小
# 功能实现部分
# 画按钮
def draw_buttons():
button_surface.fill("white")
button_surface.blit(prev_img, prev_rect)
if play_flag == 0 or play_flag == 2:
button_surface.blit(play_img, play_rect)
else:
button_surface.blit(pause_img, play_rect)
button_surface.blit(next_img, next_rect)
button_surface.blit(stop_img, stop_rect)
if loop_flag == 0:
button_surface.blit(loop_img, loop_rect)
elif loop_flag == 1:
button_surface.blit(single_loop_img, loop_rect)
elif loop_flag == 2:
button_surface.blit(random_img, loop_rect)
# 画播放列表
def draw_playlist(music_play = -1):
global music_list
play_list_surface.fill("gray")
for index, music in enumerate(music_list):
if index == music_play:
music_surface = play_list_font.render(music, True, "black", "green")
else:
music_surface = play_list_font.render(music, True, "black")
height = music_surface.get_height()
play_list_surface.blit(music_surface, (10, index * (height+5) + 10))
# 画播放进度条
def draw_play_progress(mt, val = 1):
play_progress_surface.fill('white')
rect_all = pygame.Rect(5, 5, 290, 20)
rect_played = pygame.Rect(5, 5, int(290 * val), 20)
pygame.draw.rect(play_progress_surface, "gray", rect_all)
pygame.draw.rect(play_progress_surface, "pink", rect_played)
play_time_font_surface = play_time_font.render(mt, True, "red")
width, height = play_time_font_surface.get_size()
left = WINDOW_WIDTH//4 - width//2
top = PROGRESS_BAR_HEIGHT//2 - height//2
play_progress_surface.blit(play_time_font_surface, (left, top))
# 画音量条
def draw_volume_progres(val):
valume_surface.fill('white')
rect_all = pygame.Rect(5, 5, 290, 20)
rect_played = pygame.Rect(295 - int(290 * val), 5, int(290 * val), 20)
pygame.draw.rect(valume_surface, "gray", rect_all)
pygame.draw.rect(valume_surface, "pink", rect_played)
volume_font_surface = valume_font.render("val", True, "red")
width, height = volume_font_surface.get_size()
left = WINDOW_WIDTH//4 - width//2
top = PROGRESS_BAR_HEIGHT//2 - height//2
valume_surface.blit(volume_font_surface, (left, top))
def draw_all():
screen.blit(button_surface,(0,0))
screen.blit(play_progress_surface,(0, BUTTON_BAR_HEIGHT))
screen.blit(valume_surface, (WINDOW_WIDTH//2, BUTTON_BAR_HEIGHT))
screen.blit(play_list_surface, (0, BUTTON_BAR_HEIGHT + PROGRESS_BAR_HEIGHT))
pygame.display.update()
# 获取音乐目录下的所有mp3文件名
def get_all_music():
music_list = []
global music_dir
for root,dirs, files in os.walk(music_dir):
for file in files:
name, extname = os.path.splitext(file)
if extname == ".mp3":
music_list.append((file))
return music_list
# 音乐播放功能
def play_music(num):
pygame.mixer.music.load(music_dir + "/" + music_list[num])
pygame.mixer.music.play()
'''程序主体'''
pygame.init()
screen = pygame.display.set_mode(WINDOW_SIZE)
pygame.display.set_caption("简单音乐播放器 by 爱编程的章老师")
# 图片加载
play_img = pygame.image.load(PLAY_IMG_PATH).convert_alpha()
pause_img = pygame.image.load(PAUSE_IMG_PATH).convert_alpha()
stop_img = pygame.image.load(STOP_IMG_PATH).convert_alpha()
prev_img = pygame.image.load(NEXT_IMG_PATH).convert_alpha()
loop_img = pygame.image.load(LOOP_IMG_PATH).convert_alpha()
single_loop_img = pygame.image.load(SINGLE_LOOP_IMG_PATH).convert_alpha()
random_img = pygame.image.load(RANDOM_IMG_PATH).convert_alpha()
# 放缩图片大小
play_img = pygame.transform.scale(play_img, (BUTTON_SIZE,BUTTON_SIZE))
pause_img = pygame.transform.scale(pause_img, (BUTTON_SIZE,BUTTON_SIZE))
stop_img = pygame.transform.scale(stop_img, (BUTTON_SIZE,BUTTON_SIZE))
prev_img = pygame.transform.scale(prev_img, (BUTTON_SIZE,BUTTON_SIZE))
next_img = pygame.transform.flip(prev_img, True,False)
loop_img = pygame.transform.scale(loop_img, (BUTTON_SIZE,BUTTON_SIZE))
single_loop_img = pygame.transform.scale(single_loop_img, (BUTTON_SIZE,BUTTON_SIZE))
random_img = pygame.transform.scale(random_img, (BUTTON_SIZE,BUTTON_SIZE))
# 字体工具
# 字体路径
font_path = "/".join([PATH_ROOT, "src/fonts/msyh.ttf"])
# 字体对象
play_list_font = pygame.font.Font(font_path, 14)
play_time_font = pygame.font.Font(font_path, 12)
valume_font = pygame.font.Font(font_path, 12)
# surface 对象
# 按钮条surface
button_surface = pygame.Surface((WINDOW_WIDTH, BUTTON_BAR_HEIGHT))
button_surface.fill("white")
# 播放进度条
play_progress_surface = pygame.Surface((WINDOW_WIDTH//2, PROGRESS_BAR_HEIGHT))
play_progress_surface.fill("white")
# 音量条
valume_surface = pygame.Surface((WINDOW_WIDTH //2, PROGRESS_BAR_HEIGHT))
valume_surface.fill("white")
# 按钮矩形
prev_rect = pygame.Rect((70,1), (BUTTON_SIZE, BUTTON_SIZE))
play_rect = pygame.Rect((85 + BUTTON_SIZE * 1,1), (BUTTON_SIZE, BUTTON_SIZE))
next_rect = pygame.Rect((100 + BUTTON_SIZE * 2,1), (BUTTON_SIZE, BUTTON_SIZE))
stop_rect = pygame.Rect((115 + BUTTON_SIZE * 3,1), (BUTTON_SIZE, BUTTON_SIZE))
loop_rect = pygame.Rect((130 + BUTTON_SIZE * 4,1), (BUTTON_SIZE, BUTTON_SIZE))
value_rect = pygame.Rect(WINDOW_WIDTH//2 , BUTTON_BAR_HEIGHT , WINDOW_WIDTH//2 , PROGRESS_BAR_HEIGHT)
progress_rect = pygame.Rect(0, BUTTON_BAR_HEIGHT, WINDOW_WIDTH//2 , PROGRESS_BAR_HEIGHT)
# 播放列表
music_dir = "/".join([PATH_ROOT, "src/music"])
music_list = get_all_music()
play_list_surface = pygame.Surface((WINDOW_WIDTH, WINDOW_WIDTH - BUTTON_BAR_HEIGHT + PROGRESS_BAR_HEIGHT))
play_list_surface.fill("gray")
# 播放状态相关变量
music_num =-1 # 默认播放第一首歌
play_flag = 0 # 播放状态: 在播放还是暂停,还是停止
loop_flag = 0 # 循环状态:0 列表循环 1: 单曲循环 2: 随机播放
MUSIC_END = pygame.USEREVENT + 1
draw_play_progress("0")
draw_volume_progres(0.5)
draw_buttons()
draw_playlist()
draw_all()
pygame.display.update()
while 1:
# 退出事件检测
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# 鼠标按键响应
if event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = pygame.mouse.get_pos()
# 单击事件响应
if event.button == 1:
# 播放按钮响应
if play_rect.collidepoint(mouse_pos):
if play_flag == 1:
# 播放状态时点连暂停安按钮时切换为暂停状态
play_flag = 2
pygame.mixer.music.pause()
elif play_flag == 0:
# 停止状态时按播放,切换为播放状态
play_flag = 1
music_num = 0
play_music(music_num)
elif play_flag == 2:
play_flag = 1
pygame.mixer.music.unpause()
# 前一首响应
elif prev_rect.collidepoint(mouse_pos):
if loop_flag == 2:
# 随机播放的情况下,下一首哥,将随机选取
while 1:
temp = randint(0, len(music_list)-1)
if music_num == temp:
continue
music_num = temp
break
else:
music_num -= 1
if music_num < 0:
music_num = len(music_list) - 1
play_music(music_num)
# 后一首响应
elif next_rect.collidepoint(mouse_pos):
if loop_flag == 2:
# 随机播放的情况下,下一首哥,将随机选取
while 1:
temp = randint(0, len(music_list)-1)
if music_num == temp:
continue
music_num = temp
break
else:
music_num += 1
if music_num > len(music_list) - 1:
music_num = 0
play_music(music_num)
# 循环按钮
elif loop_rect.collidepoint(mouse_pos):
loop_flag = (loop_flag + 1) % 3
# 停止按钮响应
elif stop_rect.collidepoint(mouse_pos):
play_flag = 0
music_num = -1
pygame.mixer.music.stop()
# 音量滚轮响应
if value_rect.collidepoint(mouse_pos):
# 上滚增加音量
if event.button == 4:
value_num = pygame.mixer.music.get_volume()
if value_num + 0.01 > 1:
value_num = 1
else:
value_num += 0.01
pygame.mixer.music.set_volume(value_num)
# 下滚减少音量
if event.button == 5:
value_num = pygame.mixer.music.get_volume()
if value_num - 0.01 < 0:
value_num = 0
else:
value_num -= 0.01
pygame.mixer.music.set_volume(value_num)
if progress_rect.collidepoint(mouse_pos):
# 上滚增加音量
if event.button == 4:
value_num = pygame.mixer.music.get_volume()
if value_num + 0.01 > 1:
value_num = 1
else:
value_num += 0.01
# 下滚减少音量
if event.button == 5:
value_num = pygame.mixer.music.get_volume()
if value_num - 0.01 < 0:
value_num = 0
else:
value_num -= 0.01
# 一曲完毕事件响应
if event.type == MUSIC_END:
if loop_flag == 2:
# 随机播放的情况下,下一首哥,将随机选取
while 1:
temp = randint(0, len(music_list) - 1)
if music_num == temp:
continue
music_num = temp
break
elif loop_flag == 0:
music_num += 1
if music_num > len(music_list) - 1:
music_num = 0
play_music(music_num)
music_time = pygame.mixer.music.get_pos()
if music_time < 0:
music_time = 0
s = music_time//1000 % 60
m = music_time//60000
h = music_time//3600000
music_time = str(h).ljust(2, "0") + ":" +str(m).ljust(2, "0") + ":" + str(s).ljust(2, "0") + "." + str((music_time % 1000)//10).ljust(2, "0")
value_num = pygame.mixer.music.get_volume()
draw_buttons()
draw_playlist(music_num)
draw_play_progress(music_time)
draw_volume_progres(value_num)
draw_all()
pygame.time.Clock().tick(10)
文件目录结构:
-
整体结构
-
src 目录
-
fonts目录
-
img目录
-
music目录
已完成的功能
- 文件只搜索mp3格式的
- 正常播放,下一首,上一首
- 列表循环, 单曲循环,随机播放完成
- 音量大小调节完成
- 当前播放歌曲列表特殊显示
- 当前歌曲播放时间功能
待改进功能
- 列表滚动显示功能
- 歌曲时长功能
- 进度条拖动功能
演示动画
后记
这么一个300行左右代码的软件,对于新入门的朋友来说,其实已经有点长了.
代码还有很多的因为定位的读者问题, 没有做太深入的优化.
如果需要完整的代码和相应的图片资源的朋友可以留言微信或者邮箱.看到一律回复