import os
import time
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import pygame
import mutagen.mp3 # 用于获取MP3文件时长
class MusicPlayer:
def __init__(self, root):
pygame.init()
self.root = root
self.root.title("音乐播放器")
self.root.geometry("650x720")
icon_path = "music.ico" # 请替换为你的图标文件路径
if os.path.exists(icon_path):
self.root.iconbitmap(icon_path)
# 初始化pygame.mixer
pygame.mixer.init()
# 初始化变量
self.playlist = [] # 存储音乐文件路径
self.current_index = -1 # 当前播放的歌曲索引
self.is_paused = False # 是否处于暂停状态
self.is_stopped = True # 是否停止播放
self.single_loop = False
# 创建控件
self.create_widgets()
def create_widgets(self):
# 创建控件
self.frame_left = tk.Frame(self.root)
self.frame_left.pack(side=tk.TOP, fill=tk.X, expand=False)
self.frame_right = tk.Frame(self.root)
self.frame_right.pack(side=tk.BOTTOM, padx=10, pady=0, fill=tk.BOTH, expand=True)
# 播放列表
self.playlist_lb = tk.Listbox(self.frame_right, selectmode=tk.SINGLE)
self.playlist_lb.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
self.playlist_lb.bind("<Double-Button-1>", self.play_selected_song)
self.playlist_lb.bind("<Button-3>", self.show_menu) # 绑定右键菜单事件
# 滚动条
scrollbar = ttk.Scrollbar(self.playlist_lb, orient=tk.VERTICAL, command=self.playlist_lb.yview)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
self.playlist_lb.config(yscrollcommand=scrollbar.set)
# 右键菜单
self.menu = tk.Menu(self.playlist_lb, tearoff=0)
self.menu.add_command(label="删除", command=self.delete_song)
# 控制按钮
control_frame = tk.Frame(self.frame_left)
control_frame.pack(pady=5)
self.play_btn = tk.Button(control_frame, text="加载音乐", command=self.scan_and_add_music)
self.play_btn.grid(row=0, column=0, padx=10)
self.play_btn = tk.Button(control_frame, text="播放", command=self.play_music)
self.play_btn.grid(row=0, column=1, padx=10)
self.pause_btn = tk.Button(control_frame, text="暂停", command=self.pause_music)
self.pause_btn.grid(row=0, column=2, padx=10)
self.prev_btn = tk.Button(control_frame, text="上一首", command=self.play_prev_song)
self.prev_btn.grid(row=0, column=3, padx=10)
self.next_btn = tk.Button(control_frame, text="下一首", command=self.play_next_song)
self.next_btn.grid(row=0, column=4, padx=10)
self.volume_down_btn = tk.Button(control_frame, text="音量减", command=self.volume_down)
self.volume_down_btn.grid(row=0, column=5, padx=10)
self.volume_up_btn = tk.Button(control_frame, text="音量加", command=self.volume_up)
self.volume_up_btn.grid(row=0, column=6, padx=10)
self.loop_mode_btn = tk.Button(control_frame, text="单曲循环", command=self.toggle_loop_mode)
self.loop_mode_btn.grid(row=0, column=7, padx=10)
self.playlist_mode_btn = tk.Button(control_frame, text="列表循环", command=self.playlist_mode)
self.playlist_mode_btn.grid(row=0, column=8, padx=10)
# 歌曲信息和进度条
progress_bar_frame = tk.Frame(self.frame_right)
progress_bar_frame.pack(pady=1)
self.song_info_label = tk.Label(progress_bar_frame, text="")
self.song_info_label.grid(row=0, column=0, padx=0)
self.progress_bar = ttk.Progressbar(progress_bar_frame,orient=tk.HORIZONTAL, length=200, mode='determinate')
self.progress_bar.grid(row=0, column=1, padx=10)
self.progress_bar.bind("<Button-1>", self.change_position) # 绑定进度条拖动事件
def scan_and_add_music(self):
# 选择文件夹并扫描音乐文件并添加音乐到播放列表
folder_selected = filedialog.askdirectory()
if folder_selected:
for dirpath, _, files in os.walk(folder_selected):
for file in files:
if file.endswith(('.mp3', '.m4a', '.wma', '.wav', '.acc')):
self.playlist.append(os.path.join(dirpath, file))
self.playlist_lb.insert(tk.END, os.path.basename(file))
def play_music(self):
# 播放选中的歌曲或者继续播放
if self.is_stopped:
if self.current_index == -1:
self.current_index = 0
self.load_and_play_song()
elif self.is_paused:
pygame.mixer.music.unpause()
self.is_paused = False
self.update_song_info()
def pause_music(self):
# 暂停音乐
if not self.is_paused:
pygame.mixer.music.pause()
self.is_paused = True
def play_prev_song(self):
# 播放上一首歌曲
if self.current_index > 0:
self.current_index -= 1
self.load_and_play_song()
def play_next_song(self):
# 播放下一首歌曲
if self.current_index < len(self.playlist) - 1:
self.current_index += 1
self.load_and_play_song()
else:
self.current_index = 0
self.load_and_play_song()
def load_and_play_song(self):
# 加载并播放当前索引的歌曲
if self.current_index == -1 or self.current_index >= len(self.playlist):
if self.playlist:
self.current_index = 0
self.load_and_play_song()
else:
return
pygame.mixer.music.load(self.playlist[self.current_index])
pygame.mixer.music.play()
pygame.mixer.music.set_endevent(pygame.USEREVENT)
self.playlist_lb.selection_clear(0, tk.END)
self.playlist_lb.selection_set(self.current_index)
self.playlist_lb.activate(self.current_index)
self.is_stopped = False
self.is_paused = False
self.update_song_info()
self.root.after(100, self.toggle_playlist_mode)
def play_selected_song(self, event):
# 双击列表播放选中的歌曲
index = self.playlist_lb.curselection()
if index:
self.current_index = index[0]
self.load_and_play_song()
def update_song_info(self):
# 更新当前播放的歌曲信息和进度条
if not self.is_stopped:
song_path = self.playlist[self.current_index]
song_name = os.path.basename(song_path)
self.root.title(f"正在播放: {song_name}")
# 获取歌曲时长(以秒为单位)
try:
audio = mutagen.mp3.MP3(song_path)
song_length = audio.info.length
except:
song_length = 0
self.song_info_label.config(text=f"{song_name}")
self.progress_bar.config(maximum=song_length, value=0)
self.update_progress()
def update_progress(self):
# 更新进度条
if not self.is_stopped and not self.is_paused:
current_pos = pygame.mixer.music.get_pos() / 1000.0
self.progress_bar.config(value=current_pos)
self.root.after(1000, self.update_progress)
def volume_down(self):
# 减小音量
current_volume = pygame.mixer.music.get_volume()
if current_volume > 0:
pygame.mixer.music.set_volume(current_volume - 0.1)
def volume_up(self):
# 增加音量
current_volume = pygame.mixer.music.get_volume()
if current_volume < 1:
pygame.mixer.music.set_volume(current_volume + 0.1)
def toggle_loop_mode(self):
self.single_loop = not self.single_loop
mode = "单曲循环" if self.single_loop else "列表循环"
messagebox.showinfo("播放模式", f"{mode} 已启用")
def playlist_mode(self):
self.single_loop = False
messagebox.showinfo("播放模式", "列表循环已启用")
def toggle_playlist_mode(self):
# 切换列表循环模式
for event in pygame.event.get():
if event.type == pygame.USEREVENT:
# if not pygame.mixer.music.get_busy():
if self.single_loop:
self.load_and_play_song() # 单曲循环
else:
self.play_next_song() # 列表循环
self.root.after(100, self.toggle_playlist_mode)
def show_menu(self, event):
# 显示右键菜单
self.menu.post(event.x_root, event.y_root)
def delete_song(self):
# 删除选中的歌曲
selection = self.playlist_lb.curselection()
if selection:
index = int(selection[0])
del self.playlist[index]
self.playlist_lb.delete(index)
# 如果删除的是当前正在播放的歌曲,停止播放并清空信息
if index == self.current_index:
pygame.mixer.music.stop()
self.is_stopped = True
self.is_paused = False
self.current_index = -1
self.song_info_label.config(text="正在播放:")
self.root.title("音乐播放器")
# 重新加载当前歌曲信息(如果有下一首)
if self.playlist:
self.load_and_play_song()
def change_position(self, event):
# 处理进度条拖动事件
if pygame.mixer.music.get_busy():
x = event.x
length = self.progress_bar.winfo_width()
song_length = pygame.mixer.music.get_pos() / 1000.0
new_pos = x / length * song_length
pygame.mixer.music.rewind()
pygame.mixer.music.set_pos(new_pos)
def update_song_info(self):
# 更新当前播放的歌曲信息和进度条
if not self.is_stopped:
song_path = self.playlist[self.current_index]
song_name = os.path.basename(song_path)
self.root.title(f"正在播放: {song_name[:-4]}")
# 获取歌曲时长(以秒为单位)
try:
audio = mutagen.mp3.MP3(song_path)
song_length = audio.info.length
except:
song_length = 0
self.song_info_label.config(
text=f"正在播放:{song_name} - {self.format_time(0)} / {self.format_time(song_length)}")
self.progress_bar.config(maximum=song_length, value=0)
self.update_progress()
def update_progress(self):
# 更新进度条和当前播放时间
if not self.is_stopped and not self.is_paused:
current_pos = pygame.mixer.music.get_pos() / 1000.0
self.progress_bar.config(value=current_pos)
self.song_info_label.config(
text=f"{os.path.basename(self.playlist[self.current_index])[:-4]} - {self.format_time(current_pos)} / {self.format_time(self.progress_bar['maximum'])}")
self.root.after(1000, self.update_progress)
def format_time(self, seconds):
# 将秒数格式化为 mm:ss 的形式
return time.strftime('%M:%S', time.gmtime(seconds))
if __name__ == "__main__":
root = tk.Tk()
app = MusicPlayer(root)
root.mainloop()
运行效果
标签:index,playlist,tkinter,song,Python,self,current,pygame,tk From: https://blog.csdn.net/huangkai42/article/details/139808134