Pygame(二十)音乐播放器2

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)

文件目录结构:

  1. 整体结构
    image.png

  2. src 目录
    src目录

  3. fonts目录
    fonts目录

  4. img目录
    img目录

  5. music目录
    music目录

已完成的功能

  1. 文件只搜索mp3格式的
  2. 正常播放,下一首,上一首
  3. 列表循环, 单曲循环,随机播放完成
  4. 音量大小调节完成
  5. 当前播放歌曲列表特殊显示
  6. 当前歌曲播放时间功能

待改进功能

  1. 列表滚动显示功能
  2. 歌曲时长功能
  3. 进度条拖动功能

演示动画

软件演示

后记

这么一个300行左右代码的软件,对于新入门的朋友来说,其实已经有点长了.
代码还有很多的因为定位的读者问题, 没有做太深入的优化.
如果需要完整的代码和相应的图片资源的朋友可以留言微信或者邮箱.看到一律回复

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱编程的章老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值