pygame編寫(xiě)音樂(lè)播放器的實(shí)現(xiàn)代碼示例
1、準(zhǔn)備工作
ide:pycharm
python:3.7
三方包:pygame、pyinstaller、mutagen
幾首mp3格式的歌
2、開(kāi)始
2.1 設(shè)計(jì)說(shuō)明
1、包含 上一首、下一首、暫停/播放、快進(jìn)/快退、顯示當(dāng)前播放的歌曲名稱(chēng)、顯示播放進(jìn)度條
2、使用pygame.mixer
3、隨機(jī)播放磁盤(pán)某個(gè)目錄及其子目錄下的mp3文件
4、上一首、下一首用隨機(jī)選擇choice(list) 實(shí)現(xiàn)
5、進(jìn)度條用按照一定速度移動(dòng)進(jìn)度圖片來(lái)實(shí)現(xiàn),過(guò)程中處理暫停、快進(jìn)
6、歌曲快進(jìn)播放用pygame.mixer.music.play(0,d_song_time) 實(shí)現(xiàn)
7、暫停用pygame.mixer.music.pause() 實(shí)現(xiàn)
8、播放用pygame.mixer.music.unpause() 實(shí)現(xiàn)
9、用mutagen.mp3來(lái)獲取mp3信息
2.2 代碼邏輯
收集某個(gè)目錄下的所有mp3
# 收集某個(gè)目錄及子目錄下的MP3格式的文件
# 返回歌曲路徑、歌曲時(shí)長(zhǎng)
# [['E:\\musics\\Mirror_Yohee_128K.mp3', 236], ['E:\\musics\\over here_Nobigdyl_128K.mp3', 188], ['E:\\musics\\塵_薛之謙_128K.mp3', 282], ['E:\\musics\\aaa\\塵_薛之謙_128K.mp3', 282]]
def collect_songs(fidir):
musics =[]
for root, dirs, files in os.walk(fidir):
for file in files:
tmp =[]
if file.endswith('mp3'):
file = os.path.join(root,file)
song = MP3(file)
duration = round(song.info.length)
tmp.append(file)
tmp.append(duration)
musics.append(tmp)
return musics
顯示歌曲名稱(chēng)
# 把歌曲名字顯示在播放器上
def draw_song_name(music):
# 取歌曲名
music_name = music[0].split("\\")[-1]
# print(music_name)
wbk_obj = font_obj.render(music_name, True, (0, 255, 255))
k_obj = wbk_obj.get_rect()
k_obj.center = (340, 200)
screen.blit(wbk_obj, k_obj)
pygame.display.update()
播放歌曲
# 隨機(jī)播放一首歌
def sing_a_song(musics):
# 隨機(jī)選擇一首音樂(lè)
music = choice(musics)
print(type(musics))
pygame.mixer.music.load(music[0])
pygame.mixer.music.play()
print('開(kāi)始播放:%s -- %s秒'%(music[0] , str(music[1])))
return music
顯示播放進(jìn)度
# 播放進(jìn)度顯示
def move(current_time,start_time,pause_duration_time,c_music):
if pause_end_time == 0 and pause_start_time != 0:
duration_time = round(pause_start_time - start_time - pause_duration_time)
else:
duration_time = round(current_time - start_time - pause_duration_time)
song_total_time = c_music[1]
speed = (end_x-begin_x)/song_total_time
current_x = begin_x + duration_time*speed
try:
screen.blit(dian,(current_x,148))
pygame.display.update()
except:
print(current_time)
print(start_time)
print(pause_duration_time)
exit()
快進(jìn)快退功能
# 快進(jìn)快退功能 def kuaijin(jindu_x,c_music): # 要跳轉(zhuǎn)到的距離d_x d_x = jindu_x - begin_x song_total_time = c_music[1] # 要跳轉(zhuǎn)到的時(shí)間d_song_time d_song_time = round(song_total_time*(d_x/560),1) # 將歌曲快進(jìn)到d_song_time pygame.mixer.music.play(0,d_song_time)
畫(huà)播放控件
# 畫(huà)播放控件
def draw_kongjian(is_sing,is_pause):
# 畫(huà)進(jìn)度條
# 畫(huà)一條寬度為2的線,y高度為149,x從40到600,顏色為(0,100,100)
pygame.draw.line(screen, (0, 100, 100), (40, 149), (600, 149), 2)
# 畫(huà)播放、暫停按鈕
# 先畫(huà)圓邊框,半徑20
pygame.draw.circle(screen, (0, 255, 255), (x + 80, 100), 20, 2)
# 畫(huà)三角形,開(kāi)始播放
pygame.draw.line(screen, (0, 255, 255), (x + 73.7, 107.5), (x + 73.7, 93), 2) # 豎線
# 如果正在播放且沒(méi)有暫停
if is_sing and not is_pause:
# 隱藏三角形
pygame.draw.line(screen, (0, 89, 115), (x + 73.7, 107.5), (x + 87.3, 100), 2)
pygame.draw.line(screen, (0, 89, 115), (x + 73.7, 93), (x + 87.3, 100), 2)
# 顯示第二條豎線
pygame.draw.line(screen,(0,255,255),(x+83.7,107.5),(x+83.7,93),2)
else:
# 隱藏第二條豎線
pygame.draw.line(screen, (0, 89, 115), (x + 83.7, 107.5), (x + 83.7, 93), 2)
# 顯示三角形
pygame.draw.line(screen,(0,255,255),(x+73.7,107.5),(x+87.3,100),2)
pygame.draw.line(screen,(0,255,255),(x+73.7,93),(x+87.3,100),2)
# 畫(huà)上一首按鈕
pygame.draw.line(screen, (0, 255, 255), (x - 10, 110), (x - 10, 90), 2)
pygame.draw.line(screen, (0, 255, 255), (x - 10, 100), (x + 10, 115), 2)
pygame.draw.line(screen, (0, 255, 255), (x - 10, 100), (x + 10, 85), 2)
pygame.draw.line(screen, (0, 255, 255), (x + 10, 115), (x + 10, 85), 2)
# 畫(huà)下一首按鈕
pygame.draw.line(screen, (0, 255, 255), (x + 170, 110), (x + 170, 90), 2)
pygame.draw.line(screen, (0, 255, 255), (x + 170, 100), (x + 150, 115), 2)
pygame.draw.line(screen, (0, 255, 255), (x + 170, 100), (x + 150, 85), 2)
pygame.draw.line(screen, (0, 255, 255), (x + 150, 115), (x + 150, 85), 2)
主邏輯
1、畫(huà)界面
2、如果沒(méi)有在播放音樂(lè),播放之
3、如果正在播放音樂(lè),刷新播放進(jìn)度
4、點(diǎn)擊了上一首的處理
5、點(diǎn)擊了暫停/播放的處理
6、點(diǎn)擊了下一首的處理
7、快進(jìn)/快退的處理
while True:
# 第一步畫(huà)背景
screen.fill((0, 0, 0)) # ----------------新添加
# 第二步添加背景圖片
bg = pygame.image.load(music_bg)
screen.blit(bg, (0, 0))
# 第四步,畫(huà)控件
draw_kongjian(is_sing,is_pause)
# print("status:-------" + str(pygame.mixer.music.get_busy()))
# 如果正在播放音樂(lè),有bug == 當(dāng)暫停后返回依舊是1
if pygame.mixer.music.get_busy() == 1:
is_sing = True
else:
is_sing = False
# 如果沒(méi)有在播放音樂(lè)
if not is_sing:
# 第五步,開(kāi)始唱歌
c_music = sing_a_song(musics)
# 記錄開(kāi)始播放時(shí)間
start_time = time.time()
# 暫停時(shí)長(zhǎng)置為0
pause_start_time = pause_end_time = pause_duration_time = 0
# 進(jìn)度條開(kāi)始位置重置為40
begin_x = 40
# 第六步,顯示歌名
draw_song_name(c_music)
# 更改播放狀態(tài)
is_sing = not is_sing
# 如果正在唱歌
else:
# 第六步,顯示歌名
draw_song_name(c_music)
current_time = time.time()
move(current_time, start_time, pause_duration_time, c_music)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
exit()
if event.type == MOUSEBUTTONDOWN:
# 如果點(diǎn)擊了鼠標(biāo)左鍵,取到當(dāng)前鼠標(biāo)的坐標(biāo)
pressed_array = pygame.mouse.get_pressed()
if pressed_array[0] == 1:
mouse_x, mouse_y = event.pos
print('點(diǎn)擊了左鍵,位置為(%d,%d)'%(mouse_x,mouse_y))
# 判斷點(diǎn)擊了哪個(gè)按鈕
if 80 < mouse_y < 120:
if x - 5 < mouse_x < x + 15:
# 點(diǎn)擊了上一首
c_music = sing_a_song(musics)
is_pause = False
is_kuaijin = False
# 記錄開(kāi)始時(shí)間
start_time = time.time()
# 暫停時(shí)長(zhǎng)置為0
pause_start_time = pause_end_time = pause_duration_time = 0
# 進(jìn)度條開(kāi)始位置置為40
begin_x = 40
# 第六步,顯示歌名
draw_song_name(c_music)
print('點(diǎn)擊了上一首')
elif x+60 < mouse_x < x+100:
# 修改是否暫停的狀態(tài)
is_pause = not is_pause
# 如果沒(méi)有暫停
if not is_pause:
# 開(kāi)始播放
pygame.mixer.music.unpause()
# 記錄結(jié)束暫定時(shí)間
pause_end_time = time.time()
# 計(jì)算暫停時(shí)長(zhǎng)
pause_duration_time = pause_duration_time + pause_end_time - pause_start_time
# 暫停結(jié)束,暫停結(jié)束開(kāi)始時(shí)間均置為0
pause_end_time = pause_start_time = 0
# 如果暫停了
else:
# 暫停播放
pygame.mixer.music.pause()
# 記錄開(kāi)始暫定時(shí)間
pause_start_time = time.time()
print('點(diǎn)擊了暫停')
elif x+145 < mouse_x < x+170:
# 點(diǎn)擊了下一首
c_music = sing_a_song(musics)
is_pause = False
is_kuaijin = False
# 記錄開(kāi)始時(shí)間
start_time = time.time()
# 暫停時(shí)長(zhǎng)置為0
pause_start_time = pause_end_time = pause_duration_time =0
# 進(jìn)度條開(kāi)始位置置為40
begin_x = 40
# 第六步,顯示歌名
draw_song_name(c_music)
print('點(diǎn)擊了下一首')
# 如果點(diǎn)了進(jìn)度條的某個(gè)位置
elif 155> mouse_y >145:
kuaijin(mouse_x,c_music)
begin_x = mouse_x
pause_end_time = pause_start_time = pause_duration_time = 0
move(current_time,start_time,pause_duration_time,c_music)
is_kuaijin = True
print("快進(jìn)")
pygame.display.update()
3、效果圖

刺猬牛逼?。。?/p>
4、完整代碼
#-*- coding: utf-8 -*-
import os,time,sys
from sys import exit
import pygame
from pygame.locals import *
from mutagen.mp3 import MP3
from random import choice
def rp(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
pygame.init()
screen = pygame.display.set_mode((640, 480), 0, 32)
pygame.display.set_caption("music")
# 初始化音樂(lè)播放器
pygame.mixer.init()
# 背景圖片
music_bg = rp(os.path.join('src','music_bg.jpg'))
# 進(jìn)度點(diǎn)圖片
dian_filename = rp(os.path.join('src','dian.jpg'))
dian = pygame.image.load(dian_filename)
# 字體
font_obj = pygame.font.Font('C:\Windows\Fonts\simsun.ttc',20)
# 偏移量基礎(chǔ)值
x = 80
# 進(jìn)度條開(kāi)始x坐標(biāo)
begin_x = 40
# 進(jìn)度條結(jié)束x坐標(biāo)
end_x = 600
# 是否正在播放歌曲,默認(rèn)未播放
is_sing = False
# 是否暫停,默認(rèn)未暫停
is_pause = False
# 是否快進(jìn)了
is_kuaijin = False
# 快進(jìn)后x坐標(biāo)
jindu_x = -1
# 定義當(dāng)前歌曲變量
global c_music
# 定義歌曲開(kāi)始播放時(shí)間、當(dāng)前時(shí)間、開(kāi)始暫停時(shí)間、結(jié)束暫停時(shí)間
global start_time, current_time, pause_start_time, pause_end_time,pause_duration_time
pause_start_time =0
pause_end_time =0
pause_duration_time =0
# 把歌曲名字顯示在播放器上
def draw_song_name(music):
# 取歌曲名
music_name = music[0].split("\\")[-1]
# print(music_name)
wbk_obj = font_obj.render(music_name, True, (0, 255, 255))
k_obj = wbk_obj.get_rect()
k_obj.center = (340, 200)
screen.blit(wbk_obj, k_obj)
pygame.display.update()
# 收集某個(gè)目錄及子目錄下的MP3格式的文件
# 返回歌曲路徑、歌曲時(shí)長(zhǎng)
# [['E:\\musics\\Mirror_Yohee_128K.mp3', 236], ['E:\\musics\\over here_Nobigdyl_128K.mp3', 188], ['E:\\musics\\塵_薛之謙_128K.mp3', 282], ['E:\\musics\\aaa\\塵_薛之謙_128K.mp3', 282]]
def collect_songs(fidir):
musics =[]
for root, dirs, files in os.walk(fidir):
for file in files:
tmp =[]
if file.endswith('mp3'):
file = os.path.join(root,file)
song = MP3(file)
duration = round(song.info.length)
tmp.append(file)
tmp.append(duration)
musics.append(tmp)
return musics
musics = collect_songs('E:\\musics')
print(musics)
# 隨機(jī)播放一首歌
def sing_a_song(musics):
# 隨機(jī)選擇一首音樂(lè)
music = choice(musics)
print(type(musics))
pygame.mixer.music.load(music[0])
pygame.mixer.music.play()
print('開(kāi)始播放:%s -- %s秒'%(music[0] , str(music[1])))
return music
# 畫(huà)代表當(dāng)前進(jìn)度的圓點(diǎn)
# 畫(huà)一個(gè)直徑為5個(gè)圓點(diǎn),放在100,150的位置,顏色為(0,255,255)
# dian = pygame.draw.circle(screen,(0,255,255),(begin_x,150),6)
# 畫(huà)播放控件
def draw_kongjian(is_sing,is_pause):
# 畫(huà)進(jìn)度條
# 畫(huà)一條寬度為2的線,y高度為149,x從40到600,顏色為(0,100,100)
pygame.draw.line(screen, (0, 100, 100), (40, 149), (600, 149), 2)
# 畫(huà)播放、暫停按鈕
# 先畫(huà)圓邊框,半徑20
pygame.draw.circle(screen, (0, 255, 255), (x + 80, 100), 20, 2)
# 畫(huà)三角形,開(kāi)始播放
pygame.draw.line(screen, (0, 255, 255), (x + 73.7, 107.5), (x + 73.7, 93), 2) # 豎線
# 如果正在播放且沒(méi)有暫停
if is_sing and not is_pause:
# 隱藏三角形
pygame.draw.line(screen, (0, 89, 115), (x + 73.7, 107.5), (x + 87.3, 100), 2)
pygame.draw.line(screen, (0, 89, 115), (x + 73.7, 93), (x + 87.3, 100), 2)
# 顯示第二條豎線
pygame.draw.line(screen,(0,255,255),(x+83.7,107.5),(x+83.7,93),2)
else:
# 隱藏第二條豎線
pygame.draw.line(screen, (0, 89, 115), (x + 83.7, 107.5), (x + 83.7, 93), 2)
# 顯示三角形
pygame.draw.line(screen,(0,255,255),(x+73.7,107.5),(x+87.3,100),2)
pygame.draw.line(screen,(0,255,255),(x+73.7,93),(x+87.3,100),2)
# 畫(huà)上一首按鈕
pygame.draw.line(screen, (0, 255, 255), (x - 10, 110), (x - 10, 90), 2)
pygame.draw.line(screen, (0, 255, 255), (x - 10, 100), (x + 10, 115), 2)
pygame.draw.line(screen, (0, 255, 255), (x - 10, 100), (x + 10, 85), 2)
pygame.draw.line(screen, (0, 255, 255), (x + 10, 115), (x + 10, 85), 2)
# 畫(huà)下一首按鈕
pygame.draw.line(screen, (0, 255, 255), (x + 170, 110), (x + 170, 90), 2)
pygame.draw.line(screen, (0, 255, 255), (x + 170, 100), (x + 150, 115), 2)
pygame.draw.line(screen, (0, 255, 255), (x + 170, 100), (x + 150, 85), 2)
pygame.draw.line(screen, (0, 255, 255), (x + 150, 115), (x + 150, 85), 2)
# 播放進(jìn)度顯示
def move(current_time,start_time,pause_duration_time,c_music):
if pause_end_time == 0 and pause_start_time != 0:
duration_time = round(pause_start_time - start_time - pause_duration_time)
else:
duration_time = round(current_time - start_time - pause_duration_time)
song_total_time = c_music[1]
speed = (end_x-begin_x)/song_total_time
current_x = begin_x + duration_time*speed
try:
screen.blit(dian,(current_x,148))
pygame.display.update()
except:
print(current_time)
print(start_time)
print(pause_duration_time)
exit()
# 快進(jìn)快退功能
def kuaijin(jindu_x,c_music):
# 要跳轉(zhuǎn)到的距離d_x
d_x = jindu_x - begin_x
song_total_time = c_music[1]
# 要跳轉(zhuǎn)到的時(shí)間d_song_time
d_song_time = round(song_total_time*(d_x/560),1)
# 將歌曲快進(jìn)到d_song_time
pygame.mixer.music.play(0,d_song_time)
while True:
# 第一步畫(huà)背景
screen.fill((0, 0, 0)) # ----------------新添加
# 第二步添加背景圖片
bg = pygame.image.load(music_bg)
screen.blit(bg, (0, 0))
# 第四步,畫(huà)控件
draw_kongjian(is_sing,is_pause)
# print("status:-------" + str(pygame.mixer.music.get_busy()))
# 如果正在播放音樂(lè),有bug == 當(dāng)暫停后返回依舊是1
if pygame.mixer.music.get_busy() == 1:
is_sing = True
else:
is_sing = False
# 如果沒(méi)有在播放音樂(lè)
if not is_sing:
# 第五步,開(kāi)始唱歌
c_music = sing_a_song(musics)
# 記錄開(kāi)始播放時(shí)間
start_time = time.time()
# 暫停時(shí)長(zhǎng)置為0
pause_start_time = pause_end_time = pause_duration_time = 0
# 進(jìn)度條開(kāi)始位置重置為40
begin_x = 40
# 第六步,顯示歌名
draw_song_name(c_music)
# 更改播放狀態(tài)
is_sing = not is_sing
# 如果正在唱歌
else:
# 第六步,顯示歌名
draw_song_name(c_music)
current_time = time.time()
move(current_time, start_time, pause_duration_time, c_music)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
exit()
if event.type == MOUSEBUTTONDOWN:
# 如果點(diǎn)擊了鼠標(biāo)左鍵,取到當(dāng)前鼠標(biāo)的坐標(biāo)
pressed_array = pygame.mouse.get_pressed()
if pressed_array[0] == 1:
mouse_x, mouse_y = event.pos
print('點(diǎn)擊了左鍵,位置為(%d,%d)'%(mouse_x,mouse_y))
# 判斷點(diǎn)擊了哪個(gè)按鈕
if 80 < mouse_y < 120:
if x - 5 < mouse_x < x + 15:
# 點(diǎn)擊了上一首
c_music = sing_a_song(musics)
is_pause = False
is_kuaijin = False
# 記錄開(kāi)始時(shí)間
start_time = time.time()
# 暫停時(shí)長(zhǎng)置為0
pause_start_time = pause_end_time = pause_duration_time = 0
# 進(jìn)度條開(kāi)始位置置為40
begin_x = 40
# 第六步,顯示歌名
draw_song_name(c_music)
print('點(diǎn)擊了上一首')
elif x+60 < mouse_x < x+100:
# 修改是否暫停的狀態(tài)
is_pause = not is_pause
# 如果沒(méi)有暫停
if not is_pause:
# 開(kāi)始播放
pygame.mixer.music.unpause()
# 記錄結(jié)束暫定時(shí)間
pause_end_time = time.time()
# 計(jì)算暫停時(shí)長(zhǎng)
pause_duration_time = pause_duration_time + pause_end_time - pause_start_time
# 暫停結(jié)束,暫停結(jié)束開(kāi)始時(shí)間均置為0
pause_end_time = pause_start_time = 0
# 如果暫停了
else:
# 暫停播放
pygame.mixer.music.pause()
# 記錄開(kāi)始暫定時(shí)間
pause_start_time = time.time()
print('點(diǎn)擊了暫停')
elif x+145 < mouse_x < x+170:
# 點(diǎn)擊了下一首
c_music = sing_a_song(musics)
is_pause = False
is_kuaijin = False
# 記錄開(kāi)始時(shí)間
start_time = time.time()
# 暫停時(shí)長(zhǎng)置為0
pause_start_time = pause_end_time = pause_duration_time =0
# 進(jìn)度條開(kāi)始位置置為40
begin_x = 40
# 第六步,顯示歌名
draw_song_name(c_music)
print('點(diǎn)擊了下一首')
# 如果點(diǎn)了進(jìn)度條的某個(gè)位置
elif 155> mouse_y >145:
kuaijin(mouse_x,c_music)
begin_x = mouse_x
pause_end_time = pause_start_time = pause_duration_time = 0
move(current_time,start_time,pause_duration_time,c_music)
is_kuaijin = True
print("快進(jìn)")
pygame.display.update()
5、打包為exe
請(qǐng)查看另一篇文章
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Python3-異步進(jìn)程回調(diào)函數(shù)(callback())介紹
這篇文章主要介紹了Python3-異步進(jìn)程回調(diào)函數(shù)(callback())介紹,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-05-05
使用Keras畫(huà)神經(jīng)網(wǎng)絡(luò)準(zhǔn)確性圖教程
這篇文章主要介紹了使用Keras畫(huà)神經(jīng)網(wǎng)絡(luò)準(zhǔn)確性圖教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-06-06
python類(lèi)方法中的self關(guān)鍵字使用
這篇文章主要介紹了python類(lèi)方法中的self關(guān)鍵字使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12
ansible-playbook實(shí)現(xiàn)自動(dòng)部署KVM及安裝python3的詳細(xì)教程
這篇文章主要介紹了ansible-playbook實(shí)現(xiàn)自動(dòng)部署KVM及安裝python3的詳細(xì)教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-05-05
解決Python 遍歷字典時(shí)刪除元素報(bào)異常的問(wèn)題
下面小編就為大家?guī)?lái)一篇解決Python 遍歷字典時(shí)刪除元素報(bào)異常的問(wèn)題。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-09-09
python實(shí)現(xiàn)逐個(gè)讀取txt字符并修改
今天小編就為大家分享一篇python實(shí)現(xiàn)逐個(gè)讀取txt字符并修改,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-12-12
Python文件讀寫(xiě)處理日常任務(wù)終極工具實(shí)例
Python文件的讀寫(xiě)操作時(shí),有很多需要考慮的細(xì)節(jié),這包括文件打開(kāi)方式、讀取和寫(xiě)入數(shù)據(jù)的方法、異常處理等,在本文中,將深入探討Python中的文件操作,旨在提供全面的指南,幫你充分了解Python文件的讀寫(xiě)2023-11-11

