基于Python中的tkinter和pygame库创建一个简单音乐播放器

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("500x600")
        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=2, 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(padx=0, 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=2)

        self.play_btn = tk.Button(control_frame, text="播放", command=self.play_music)
        self.play_btn.grid(row=0, column=1, padx=2)

        self.pause_btn = tk.Button(control_frame, text="暂停", command=self.pause_music)
        self.pause_btn.grid(row=0, column=2, padx=2)

        self.prev_btn = tk.Button(control_frame, text="上一首", command=self.play_prev_song)
        self.prev_btn.grid(row=0, column=3, padx=2)

        self.next_btn = tk.Button(control_frame, text="下一首", command=self.play_next_song)
        self.next_btn.grid(row=0, column=4, padx=2)

        self.volume_down_btn = tk.Button(control_frame, text="音量减", command=self.volume_down)
        self.volume_down_btn.grid(row=0, column=5, padx=2)

        self.volume_up_btn = tk.Button(control_frame, text="音量加", command=self.volume_up)
        self.volume_up_btn.grid(row=0, column=6, padx=2)

        self.loop_mode_btn = tk.Button(control_frame, text="单曲循环", command=self.toggle_loop_mode)
        self.loop_mode_btn.grid(row=0, column=7, padx=2)

        self.playlist_mode_btn = tk.Button(control_frame, text="列表循环", command=self.playlist_mode)
        self.playlist_mode_btn.grid(row=0, column=8, padx=2)

        # 歌曲信息和进度条
        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=150, mode='determinate')
        self.progress_bar.grid(row=0, column=1, padx=2)
        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()

运行效果

  • 16
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值