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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容