Pygame(二十)音樂播放器2

Pygame(二十)音樂播放器2

接上節(jié)內(nèi)容:

# /usr/bin/python3

# Author: 愛編程的章老師
# @Time: 2021/1/17 0017
# E-mail: Bluesand2010@163.com



import pygame
import sys
import os
from random import randint
'''音樂播放器'''
# 音樂播放/暫停/繼續(xù)/停止功能
# 實現(xiàn)播放列表顯示功能
# 實現(xiàn)單曲循環(huán)/列表循環(huán)/隨機播放功能
# 實現(xiàn)進度條拖動改變進度功能
# 實現(xiàn)音量調(diào)節(jié)




# 常量申明部分
WINDOW_SIZE = WINDOW_WIDTH, WINDOW_HEIGHT = 500, 300  # 窗體的大小設(shè)置
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"])  # 循環(huán)播放按鈕圖片路徑
SINGLE_LOOP_IMG_PATH = "/".join([PATH_ROOT, "src/img/loop1.png"])  # 循環(huán)播放按鈕圖片路徑
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  # 按鈕的大小

# 功能實現(xiàn)部分
# 畫按鈕
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")



# 播放狀態(tài)相關(guān)變量
music_num =-1 # 默認播放第一首歌
play_flag = 0 # 播放狀態(tài): 在播放還是暫停,還是停止
loop_flag = 0 # 循環(huán)狀態(tài):0 列表循環(huán) 1: 單曲循環(huán) 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()

        # 鼠標按鍵響應(yīng)
        if event.type == pygame.MOUSEBUTTONDOWN:
            mouse_pos = pygame.mouse.get_pos()

            # 單擊事件響應(yīng)
            if event.button == 1:
                # 播放按鈕響應(yīng)
                if play_rect.collidepoint(mouse_pos):
                    if play_flag == 1:
                        # 播放狀態(tài)時點連暫停安按鈕時切換為暫停狀態(tài)
                        play_flag = 2
                        pygame.mixer.music.pause()
                    elif play_flag == 0:
                        # 停止狀態(tài)時按播放,切換為播放狀態(tài)
                        play_flag = 1
                        music_num = 0
                        play_music(music_num)
                    elif play_flag == 2:
                        play_flag = 1
                        pygame.mixer.music.unpause()

                # 前一首響應(yīng)
                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)

                # 后一首響應(yīng)
                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)

                # 循環(huán)按鈕
                elif loop_rect.collidepoint(mouse_pos):
                    loop_flag = (loop_flag + 1) % 3

                # 停止按鈕響應(yīng)
                elif stop_rect.collidepoint(mouse_pos):
                    play_flag = 0
                    music_num = -1
                    pygame.mixer.music.stop()

            # 音量滾輪響應(yīng)
            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

            # 一曲完畢事件響應(yīng)
            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)

文件目錄結(jié)構(gòu):

  1. 整體結(jié)構(gòu)


    image.png
  2. src 目錄


    src目錄
  3. fonts目錄


    fonts目錄
  4. img目錄


    img目錄
  5. music目錄


    music目錄

已完成的功能

  1. 文件只搜索mp3格式的
  2. 正常播放,下一首,上一首
  3. 列表循環(huán), 單曲循環(huán),隨機播放完成
  4. 音量大小調(diào)節(jié)完成
  5. 當前播放歌曲列表特殊顯示
  6. 當前歌曲播放時間功能

待改進功能

  1. 列表滾動顯示功能
  2. 歌曲時長功能
  3. 進度條拖動功能

演示動畫

軟件演示

后記

這么一個300行左右代碼的軟件,對于新入門的朋友來說,其實已經(jīng)有點長了.
代碼還有很多的因為定位的讀者問題, 沒有做太深入的優(yōu)化.
如果需要完整的代碼和相應(yīng)的圖片資源的朋友可以留言微信或者郵箱.看到一律回復(fù)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市娇唯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌瞻赶,老刑警劉巖谆棺,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件叹螟,死亡現(xiàn)場離奇詭異,居然都是意外死亡秸侣,警方通過查閱死者的電腦和手機存筏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來味榛,“玉大人椭坚,你說我怎么就攤上這事〔” “怎么了善茎?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長频轿。 經(jīng)常有香客問我垂涯,道長,這世上最難降的妖魔是什么航邢? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任耕赘,我火速辦了婚禮,結(jié)果婚禮上膳殷,老公的妹妹穿的比我還像新娘操骡。我一直安慰自己,他們只是感情好赚窃,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布册招。 她就那樣靜靜地躺著,像睡著了一般考榨。 火紅的嫁衣襯著肌膚如雪跨细。 梳的紋絲不亂的頭發(fā)上鹦倚,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天河质,我揣著相機與錄音,去河邊找鬼震叙。 笑死掀鹅,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的媒楼。 我是一名探鬼主播乐尊,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼划址!你這毒婦竟也來了扔嵌?” 一聲冷哼從身側(cè)響起限府,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎痢缎,沒想到半個月后胁勺,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡独旷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年署穗,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嵌洼。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡案疲,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出麻养,到底是詐尸還是另有隱情褐啡,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布鳖昌,位于F島的核電站春贸,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏遗遵。R本人自食惡果不足惜萍恕,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望车要。 院中可真熱鬧允粤,春花似錦、人聲如沸翼岁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽琅坡。三九已至悉患,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間榆俺,已是汗流浹背售躁。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留茴晋,地道東北人陪捷。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像诺擅,于是被迫代替她去往敵國和親市袖。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容