当前位置: 首页 > news >正文

Python开发可视化音乐播放器教程(附代码)

 

在日常使用电脑听本地音乐时,很多人会遇到系统播放器无法自动切歌、歌单管理混乱的问题。本文将以零基础视角,带你用Python快速开发一款功能完整的可视化音乐播放器,支持文件夹选择、模糊搜索、分页展示与循环播放,最终还能打包成独立exe文件,脱离Python环境直接使用。

 

一、开发前准备:环境搭建与工具选择

 

开发这款播放器仅需两个核心工具,零基础也能快速上手:

 

1. Python环境:前往Python官网下载3.8及以上版本,安装时务必勾选“Add Python to PATH”,确保后续能在命令行直接调用Python。

2. AI辅助工具:推荐使用DeepSeek等AI工具生成初始代码并解决报错,只需清晰描述需求(如“开发带分页和模糊搜索的本地音乐播放器”),即可大幅降低编码难度。

 

核心依赖库仅需2个,后续会通过命令行安装:

 

- Pygame:负责音频解码与播放,支持MP3、WAV等主流格式。

- Tkinter:Python自带的GUI库,用于构建可视化界面,无需额外安装。

- PIL(Pillow):可选,用于处理界面中的图片资源,本文基础版本暂不涉及。

 

二、核心功能实现:从代码解析到问题修复

 

1. 初始代码生成与结构解析

 

向AI工具提交需求后,会得到基于类封装的核心代码,整体结构分为3部分:

 

- 初始化模块:创建窗口、初始化Pygame音频引擎、定义核心变量(如当前播放索引、分页参数)。

 

python

class MusicPlayer:

    def __init__(self, root):

        self.root = root

        self.root.title("Python音乐播放器")

        self.root.geometry("800x600") # 窗口大小

        self.root.configure(bg='#2C3E50') # 深色背景,提升视觉体验

        

        # 初始化Pygame音频

        try:

            pygame.mixer.init()

            print("音频引擎初始化成功")

        except Exception as e:

            messagebox.showerror("错误", f"音频初始化失败:{e}")

        

        # 核心变量定义

        self.music_folder = "" # 音乐文件夹路径

        self.music_files = [] # 音乐文件列表

        self.current_index = 0 # 当前播放索引

        self.is_playing = False # 播放状态

        self.current_page = 1 # 当前分页

        self.songs_per_page = 15 # 每页显示歌曲数(后续优化为11)

        self.loop_mode = False # 循环播放开关

 

 

- UI构建模块:通过Tkinter创建按钮、列表框、搜索框等控件,实现“选择文件夹”“上一首/下一首”“循环切换”等交互入口。

- 功能逻辑模块:实现音乐加载、播放控制、分页计算、模糊搜索等核心功能,例如通过 os.listdir() 读取文件夹内音频文件,通过 pygame.mixer.music.play() 实现播放。

 

2. 常见报错与解决方案

 

零基础开发时,报错是常态,以下是本文遇到的典型问题及解决方法:

 

(1)[Errno 2] No such file or directory(文件路径错误)

 

原因:未选择音乐文件夹,或代码中路径拼接错误。

解决:

 

- 确保先点击“选择文件夹”按钮,指定正确的音乐存放路径。

- 检查代码中 os.path.join(self.music_folder, file) 是否正确拼接路径,避免因文件夹路径为空导致错误。

 

(2)No module named 'pygame'(库未安装)

 

原因:Python环境中缺少Pygame库。

解决:

 

1. 按下 Win+R 打开命令提示符,输入 cmd 进入终端。

2. 执行安装命令(国内推荐使用清华镜像源,速度更快):

 

bash

pip install pygame -i https://pypi.tuna.tsinghua.edu.cn/simple

 

 

3. 若提示“权限不足”,追加 --user 参数: pip install pygame --user -i 镜像源地址 。

 

(3)界面出现两个暂停按钮/无循环功能

 

原因:AI生成的初始代码可能存在UI控件重复或功能遗漏。

解决:向AI提交优化需求(如“删除多余暂停按钮,增加循环播放功能”),AI会自动修正代码,例如:

 

- 删除重复的 tk.Button(..., text="暂停") 控件。

- 新增循环控制逻辑:在 toggle_loop() 方法中切换 self.loop_mode 状态,并更新按钮文本为“循环:开/关”。

 

三、功能优化:让播放器更实用

 

初始版本完成后,可根据需求进一步优化,本文主要做了3点改进:

 

1. 分页调整:将 self.songs_per_page 从15改为11,避免因歌曲过多导致界面滚动条过长。

2. 循环播放:新增 loop_btn 按钮,点击时切换 self.loop_mode 状态,播放结束后通过 monitor_playback() 方法判断是否重新播放当前歌曲:

 

python

def monitor_playback(self):

    # 监听播放状态,播放结束后自动切歌或循环

    while self.is_playing:

        if not pygame.mixer.music.get_busy() and not self.is_paused:

            if self.loop_mode:

                self.play_music() # 循环模式:重新播放当前歌曲

            else:

                self.next_song() # 顺序模式:播放下一首

            break

        time.sleep(0.1) # 避免占用过多CPU资源

 

 

3. 模糊搜索:通过 self.search_entry.get() 获取搜索关键词,遍历 self.music_files 筛选包含关键词的歌曲,实现实时搜索:

 

python

def search_music(self, event=None):

    search_term = self.search_entry.get().strip().lower()

    if search_term:

        self.search_results = [song for song in self.music_files if search_term in song.lower()]

        self.is_searching = True

    else:

        self.is_searching = False

    self.update_songs_list() # 刷新列表框,显示搜索结果

 

 

四、打包成exe:脱离Python环境运行

 

开发完成后,为了方便在其他电脑上使用,需要将 .py 文件打包成独立的 .exe 应用程序,推荐使用PyInstaller工具:

 

1. 安装PyInstaller

 

在命令提示符中执行:

 

bash

pip install pyinstaller -i https://pypi.tuna.tsinghua.edu.cn/simple

 

 

2. 执行打包命令

 

1. 进入代码所在文件夹(例如桌面: cd desktop )。

2. 执行打包命令,核心参数说明:

 

-  --onefile :打包成单个exe文件(便于传输)。

-  --windowed :不显示终端窗口(避免运行时弹出黑色命令框)。

-  --name :指定exe文件名称(如“音乐播放器”)。

-  --hidden-import=pygame :确保Pygame库被正确打包。

 

完整命令:

 

bash

pyinstaller 音乐播放器.py --onefile --windowed --name="音乐播放器" --hidden-import=pygame --clean

 

 

3. 找到exe文件

 

打包完成后,在代码所在文件夹会生成 dist 文件夹,打开即可看到“音乐播放器.exe”,双击即可运行,无需依赖Python环境。

 

五、总结与扩展方向

 

本文通过“AI生成代码+报错修复+功能优化+打包发布”的流程,实现了一款零基础可上手的Python音乐播放器。核心亮点在于:

 

- 全程无需深入编写代码,只需用自然语言描述需求,AI即可完成大部分工作。

- 解决了系统播放器的痛点,支持本地音乐管理、模糊搜索、循环播放等实用功能。

 

若想进一步提升,可尝试这些扩展方向:

 

- 增加音量调节滑块:通过 pygame.mixer.music.set_volume() 实现音量控制。

- 支持歌词显示:解析LRC歌词文件,同步显示歌词内容。

- 美化界面:使用Pillow库添加背景图片,或用PyQt替代Tkinter,打造更现代的UI。

 

以下是经过优化后的完整代码,包含文件夹选择、模糊搜索、分页(每页11首)、循环播放等所有核心功能,可直接复制使用。

import os
import tkinter as tk
from tkinter import filedialog, messagebox
import threading
import time

# 尝试导入pygame音频库,无则提示功能受限
try:
    from pygame import mixer
    PYGAME_AVAILABLE = True
except ImportError:
    PYGAME_AVAILABLE = False
    print("pygame未安装,播放功能将不可用")

class MusicPlayer:
    def __init__(self, root):
        self.root = root
        self.root.title("Python音乐播放器")
        self.root.geometry("800x600")  # 固定窗口大小
        self.root.configure(bg='#2C3E50')  # 深色背景,提升视觉体验

        # 初始化音频系统,失败则进入降级模式
        if PYGAME_AVAILABLE:
            try:
                mixer.init()
                print("音频系统初始化成功")
            except Exception as e:
                print(f"音频系统初始化失败: {e}")
                self.setup_fallback_mode()
                return
        else:
            self.setup_fallback_mode()
            return

        # 音乐核心变量
        self.music_folder = ""  # 选中的音乐文件夹路径
        self.music_files = []  # 存储音乐文件名列表
        self.current_index = 0  # 当前播放歌曲索引
        self.is_playing = False  # 播放状态标记
        self.is_paused = False  # 暂停状态标记
        self.current_page = 1  # 当前分页
        self.songs_per_page = 11  # 每页显示11首歌(优化后)
        self.total_pages = 1  # 总页数
        self.loop_mode = False  # 循环播放开关

        # 搜索功能变量
        self.search_results = []  # 搜索结果列表
        self.is_searching = False  # 搜索状态标记

        # 生成界面控件
        self.create_ui()

    def setup_fallback_mode(self):
        """pygame不可用时的降级模式:仅显示文件列表,禁用播放功能"""
        self.music_folder = ""
        self.music_files = []
        self.current_index = 0
        self.is_playing = False
        self.is_paused = False
        self.current_page = 1
        self.songs_per_page = 11
        self.total_pages = 1
        self.loop_mode = False
        self.search_results = []
        self.is_searching = False

        self.create_ui()
        # 禁用所有播放控制按钮
        self.play_btn.config(state=tk.DISABLED)
        self.loop_btn.config(state=tk.DISABLED)
        self.prev_btn.config(state=tk.DISABLED)
        self.next_btn.config(state=tk.DISABLED)
        # 弹出提示
        messagebox.showwarning("功能限制", 
                              "无法初始化音频系统。程序将以只读模式运行,可以浏览音乐文件但无法播放。\n\n请安装pygame库:pip install pygame")

    def create_ui(self):
        """创建所有界面控件:标题、文件夹选择、搜索、歌单、播放控制等"""
        # 1. 标题区域
        title_label = tk.Label(
            self.root, 
            text="Python音乐播放器", 
            font=("Arial", 20, "bold"), 
            bg='#2C3E50', 
            fg='#ECF0F1'
        )
        title_label.pack(pady=10)

        # 2. 文件夹选择区域
        folder_frame = tk.Frame(self.root, bg='#2C3E50')
        folder_frame.pack(pady=10, fill='x', padx=20)
        
        self.folder_label = tk.Label(
            folder_frame, 
            text="未选择音乐文件夹", 
            font=("Arial", 10), 
            bg='#34495E', 
            fg='#ECF0F1', 
            width=60, 
            anchor='w', 
            padx=10
        )
        self.folder_label.pack(side=tk.LEFT, padx=(0, 10))
        
        select_folder_btn = tk.Button(
            folder_frame, 
            text="选择文件夹", 
            font=("Arial", 10), 
            command=self.select_folder, 
            bg='#3498DB', 
            fg='white'
        )
        select_folder_btn.pack(side=tk.RIGHT)

        # 3. 搜索区域
        search_frame = tk.Frame(self.root, bg='#2C3E50')
        search_frame.pack(pady=10, fill='x', padx=20)
        
        search_label = tk.Label(
            search_frame, 
            text="搜索:", 
            font=("Arial", 10), 
            bg='#2C3E50', 
            fg='#ECF0F1'
        )
        search_label.pack(side=tk.LEFT, padx=(0, 10))
        
        self.search_entry = tk.Entry(
            search_frame, 
            font=("Arial", 10), 
            width=40
        )
        self.search_entry.pack(side=tk.LEFT, padx=(0, 10))
        self.search_entry.bind('<KeyRelease>', self.search_music)  # 实时搜索
        
        clear_search_btn = tk.Button(
            search_frame, 
            text="清除搜索", 
            font=("Arial", 10), 
            command=self.clear_search, 
            bg='#E74C3C', 
            fg='white'
        )
        clear_search_btn.pack(side=tk.LEFT)

        # 4. 歌单区域(含分页)
        songs_frame = tk.Frame(self.root, bg='#2C3E50')
        songs_frame.pack(pady=10, fill='both', expand=True, padx=20)
        
        # 歌单标题
        songs_title = tk.Label(
            songs_frame, 
            text="歌单", 
            font=("Arial", 14, "bold"), 
            bg='#2C3E50', 
            fg='#ECF0F1'
        )
        songs_title.pack(anchor='w')
        
        # 歌单列表框+滚动条
        listbox_frame = tk.Frame(songs_frame, bg='#2C3E50')
        listbox_frame.pack(fill='both', expand=True, pady=10)
        
        self.songs_listbox = tk.Listbox(
            listbox_frame, 
            font=("Arial", 10), 
            bg='#34495E', 
            fg='#ECF0F1', 
            selectbackground='#3498DB'
        )
        self.songs_listbox.pack(fill='both', expand=True, side=tk.LEFT)
        
        scrollbar = tk.Scrollbar(listbox_frame, orient=tk.VERTICAL)
        scrollbar.pack(fill=tk.Y, side=tk.RIGHT)
        self.songs_listbox.config(yscrollcommand=scrollbar.set)
        scrollbar.config(command=self.songs_listbox.yview)
        
        # 双击列表项播放歌曲
        self.songs_listbox.bind('<Double-Button-1>', self.play_selected_song)

        # 分页控制按钮
        page_frame = tk.Frame(songs_frame, bg='#2C3E50')
        page_frame.pack(fill='x', pady=5)
        
        self.prev_page_btn = tk.Button(
            page_frame, 
            text="上一页", 
            font=("Arial", 10), 
            command=self.prev_page, 
            bg='#3498DB', 
            fg='white', 
            state=tk.DISABLED
        )
        self.prev_page_btn.pack(side=tk.LEFT, padx=(0, 10))
        
        self.page_label = tk.Label(
            page_frame, 
            text="第 1 页 / 共 1 页", 
            font=("Arial", 10), 
            bg='#2C3E50', 
            fg='#ECF0F1'
        )
        self.page_label.pack(side=tk.LEFT, padx=(0, 10))
        
        self.next_page_btn = tk.Button(
            page_frame, 
            text="下一页", 
            font=("Arial", 10), 
            command=self.next_page, 
            bg='#3498DB', 
            fg='white', 
            state=tk.DISABLED
        )
        self.next_page_btn.pack(side=tk.LEFT)

        # 5. 当前播放信息区域
        info_frame = tk.Frame(self.root, bg='#2C3E50')
        info_frame.pack(pady=10, fill='x', padx=20)
        
        self.current_song_label = tk.Label(
            info_frame, 
            text="当前播放: 无", 
            font=("Arial", 12), 
            bg='#2C3E50', 
            fg='#ECF0F1', 
            anchor='w'
        )
        self.current_song_label.pack(fill='x')
        
        self.mode_label = tk.Label(
            info_frame, 
            text="播放模式: 顺序播放", 
            font=("Arial", 10), 
            bg='#2C3E50', 
            fg='#BDC3C7', 
            anchor='w'
        )
        self.mode_label.pack(fill='x')

        # 6. 播放控制按钮区域
        control_frame = tk.Frame(self.root, bg='#2C3E50')
        control_frame.pack(pady=20)
        
        self.prev_btn = tk.Button(
            control_frame, 
            text="上一首", 
            font=("Arial", 12), 
            command=self.prev_song, 
            bg='#3498DB', 
            fg='white', 
            width=8
        )
        self.prev_btn.pack(side=tk.LEFT, padx=5)
        
        self.play_btn = tk.Button(
            control_frame, 
            text="播放", 
            font=("Arial", 12), 
            command=self.toggle_play, 
            bg='#2ECC71', 
            fg='white', 
            width=8
        )
        self.play_btn.pack(side=tk.LEFT, padx=5)
        
        self.next_btn = tk.Button(
            control_frame, 
            text="下一首", 
            font=("Arial", 12), 
            command=self.next_song, 
            bg='#3498DB', 
            fg='white', 
            width=8
        )
        self.next_btn.pack(side=tk.LEFT, padx=5)
        
        self.loop_btn = tk.Button(
            control_frame, 
            text="循环: 关", 
            font=("Arial", 12), 
            command=self.toggle_loop, 
            bg='#9B59B6', 
            fg='white', 
            width=8
        )
        self.loop_btn.pack(side=tk.LEFT, padx=5)

        # 7. 状态栏
        self.status_label = tk.Label(
            self.root, 
            text="准备就绪", 
            font=("Arial", 10), 
            bg='#2C3E50', 
            fg='#BDC3C7', 
            anchor='w'
        )
        self.status_label.pack(fill='x', padx=20, pady=5)

        # 初始化按钮状态
        self.update_buttons_state()

    def select_folder(self):
        """选择音乐文件夹,加载文件夹内的音频文件"""
        folder = filedialog.askdirectory(title="选择音乐文件夹")
        if folder:
            self.music_folder = folder
            self.folder_label.config(text=folder)
            self.load_music_files()  # 加载音频文件
            self.update_songs_list()  # 更新歌单列表
            self.update_buttons_state()  # 更新按钮状态
            self.status_label.config(text=f"已加载文件夹: {folder}")

    def load_music_files(self):
        """加载音乐文件夹内的音频文件(支持MP3、WAV等主流格式)"""
        self.music_files = []
        if self.music_folder and os.path.exists(self.music_folder):
            # 支持的音频格式列表
            audio_extensions = ('.mp3', '.wav', '.ogg', '.flac', '.m4a', '.aac')
            try:
                # 遍历文件夹,筛选音频文件
                for file in os.listdir(self.music_folder):
                    file_path = os.path.join(self.music_folder, file)
                    if os.path.isfile(file_path) and file.lower().endswith(audio_extensions):
                        self.music_files.append(file)
                print(f"找到 {len(self.music_files)} 个音乐文件")
            except Exception as e:
                print(f"读取文件夹时出错: {e}")
                messagebox.showerror("错误", f"读取文件夹时出错: {e}")
        else:
            print("文件夹不存在或未选择")
        
        # 计算总页数
        self.total_pages = max(1, (len(self.music_files) + self.songs_per_page - 1) // self.songs_per_page)
        self.current_page = 1  # 重置为第一页

    def update_songs_list(self):
        """更新歌单列表(支持分页和搜索结果显示)"""
        self.songs_listbox.delete(0, tk.END)  # 清空列表
        
        # 确定当前要显示的歌曲列表(搜索状态则显示搜索结果,否则显示全部)
        songs_to_show = self.search_results if self.is_searching else self.music_files
        
        # 计算当前页的歌曲索引范围
        start_index = (self.current_page - 1) * self.songs_per_page
        end_index = min(start_index + self.songs_per_page, len(songs_to_show))
        
        # 添加歌曲到列表框(显示序号+歌曲名)
        for i in range(start_index, end_index):
            song_name = songs_to_show[i]
            display_text = f"{i+1}. {song_name}"
            self.songs_listbox.insert(tk.END, display_text)
        
        # 更新分页信息
        total_items = len(songs_to_show)
        actual_pages = max(1, (total_items + self.songs_per_page - 1) // self.songs_per_page)
        self.page_label.config(text=f"第 {self.current_page} 页 / 共 {actual_pages} 页")
        
        # 更新分页按钮状态(第一页禁用上一页,最后一页禁用下一页)
        self.prev_page_btn.config(state=tk.NORMAL if self.current_page > 1 else tk.DISABLED)
        self.next_page_btn.config(state=tk.NORMAL if self.current_page < actual_pages else tk.DISABLED)

    def prev_page(self):
        """上一页:当前页大于1时,页码减1并更新列表"""
        if self.current_page > 1:
            self.current_page -= 1
            self.update_songs_list()

    def next_page(self):
        """下一页:当前页小于总页数时,页码加1并更新列表"""
        total_items = len(self.search_results) if self.is_searching else len(self.music_files)
        total_pages = max(1, (total_items + self.songs_per_page - 1) // self.songs_per_page)
        if self.current_page < total_pages:
            self.current_page += 1
            self.update_songs_list()

    def search_music(self, event=None):
        """模糊搜索:根据输入关键词筛选歌曲,实时更新列表"""
        search_term = self.search_entry.get().strip().lower()
        if not search_term:
            self.is_searching = False
            self.current_page = 1  # 重置为第一页
        else:
            self.is_searching = True
            # 筛选包含关键词的歌曲(不区分大小写)
            self.search_results = [song for song in self.music_files if search_term in song.lower()]
            self.current_page = 1  # 搜索结果重置为第一页
        self.update_songs_list()  # 更新列表显示

    def clear_search(self):
        """清除搜索:清空输入框,恢复显示全部歌曲"""
        self.search_entry.delete(0, tk.END)
        self.is_searching = False
        self.current_page = 1
        self.update_songs_list()

    def play_selected_song(self, event=None):
        """播放列表中选中的歌曲:根据选中项计算实际索引"""
        selection = self.songs_listbox.curselection()
        if selection:
            index = selection[0]  # 列表框中选中项的索引
            # 计算歌曲在实际列表中的索引(区分搜索/非搜索状态)
            if self.is_searching:
                actual_index = (self.current_page - 1) * self.songs_per_page + index
                if actual_index < len(self.search_results):
                    song_name = self.search_results[actual_index]
                    # 找到歌曲在总列表中的索引
                    try:
                        self.current_index = self.music_files.index(song_name)
                    except ValueError:
                        messagebox.showerror("错误", f"找不到歌曲: {song_name}")
                        return
            else:
                self.current_index = (self.current_page - 1) * self.songs_per_page + index
            # 播放选中的歌曲
            self.play_music()

    def play_music(self):
        """核心播放功能:加载并播放当前索引对应的歌曲"""
        if not PYGAME_AVAILABLE:
            messagebox.showwarning("功能受限", "音频播放功能不可用,请安装pygame库")
            return
        if not self.music_files:
            messagebox.showwarning("警告", "没有可播放的音乐文件")
            return
        # 确保索引在有效范围内
        if self.current_index < 0 or self.current_index >= len(self.music_files):
            self.current_index = 0
        
        # 拼接歌曲完整路径
        song_path = os.path.join(self.music_folder, self.music_files[self.current_index])
        # 检查文件是否存在
        if not os.path.exists(song_path):
            messagebox.showerror("错误", f"文件不存在: {song_path}")
            return
        
        print(f"尝试播放: {song_path}")
        try:
            # 加载并播放歌曲
            mixer.music.load(song_path)
            mixer.music.play()
            self.is_playing = True
            self.is_paused = False
            # 更新播放信息
            self.current_song_label.config(text=f"当前播放: {self.music_files[self.current_index]}")
            self.status_label.config(text=f"正在播放: {self.music_files[self.current_index]}")
            self.update_buttons_state()  # 更新按钮状态
            # 启动线程监听播放结束(守护线程,避免程序退出残留)
            threading.Thread(target=self.monitor_playback, daemon=True).start()
        except Exception as e:
            error_msg = f"无法播放音乐文件: {str(e)}"
            print(error_msg)
            messagebox.showerror("错误", error_msg)
            self.status_label.config(text=f"播放失败: {self.music_files[self.current_index]}")
            self.play_btn.config(text="播放")

    def toggle_play(self):
        """播放/暂停切换:根据当前状态切换播放或暂停"""
        if not PYGAME_AVAILABLE:
            messagebox.showwarning("功能受限", "音频播放功能不可用,请安装pygame库")
            return
        if not self.music_files:
            messagebox.showwarning("警告", "没有可播放的音乐文件")
            return
        
        if self.is_playing:
            if self.is_paused:
                # 暂停状态 -> 恢复播放
                mixer.music.unpause()
                self.is_paused = False
                self.status_label.config(text=f"正在播放: {self.music_files[self.current_index]}")
            else:
                # 播放状态 -> 暂停
                mixer.music.pause()
                self.is_paused = True
                self.status_label.config(text=f"已暂停: {self.music_files[self.current_index]}")
        else:
            # 未播放状态 -> 开始播放
            self.play_music()
        
        self.update_buttons_state()  # 更新按钮文本

    def toggle_loop(self):
        """循环播放切换:切换循环状态,更新按钮文本和模式提示"""
        self.loop_mode = not self.loop_mode
        if self.loop_mode:
            self.loop_btn.config(text="循环: 开", bg='#E74C3C')  # 红色表示循环开启
            self.mode_label.config(text="播放模式: 单曲循环")
            self.status_label.config(text="已开启单曲循环模式")
        else:
            self.loop_btn.config(text="循环: 关", bg='#9B59B6')  # 紫色表示循环关闭
            self.mode_label.config(text="播放模式: 顺序播放")
            self.status_label.config(text="已关闭循环模式")

    def prev_song(self):
        """上一首:索引减1(循环到最后一首),播放上一首歌曲"""
        if not self.music_files:
            return
        self.current_index = (self.current_index - 1) % len(self.music_files)
        self.play_music()

    def next_song(self):
        """下一首:索引加1(循环到第一首),播放下一首歌曲"""
        if not self.music_files:
            return
        self.current_index = (self.current_index + 1) % len(self.music_files)
        self.play_music()

    def monitor_playback(self):
        """监听播放状态:播放结束后自动切歌(根据循环模式判断)"""
        while self.is_playing:
            # 检查音乐是否在播放(未暂停且未播放结束)
            if not mixer.music.get_busy() and not self.is_paused:
                if self.loop_mode:
                    # 循环模式:重新播放当前歌曲
                    self.root.after(100, self.play_music)
                else:
                    # 顺序模式:播放下一首歌曲
                    self.root.after(100, self.next_song)
                break  # 退出监听线程
            time.sleep(0.1)  # 降低CPU占用

    def update_buttons_state(self):
        """更新按钮状态:根据播放/暂停状态切换按钮文本"""
        if self.is_playing and not self.is_paused:
            self.play_btn.config(text="暂停")
        else:
            self.play_btn.config(text="播放")
        
        # 启用/禁用控制按钮(无音乐文件或无pygame时禁用)
        state = tk.NORMAL if self.music_files and PYGAME_AVAILABLE else tk.DISABLED
        self.prev_btn.config(state=state)
        self.play_btn.config(state=state)
        self.next_btn.config(state=state)
        self.loop_btn.config(state=state)

# 程序入口:创建窗口并启动
if __name__ == "__main__":
    root = tk.Tk()
    app = MusicPlayer(root)
    root.mainloop()
 

http://www.dtcms.com/a/509206.html

相关文章:

  • 【u-boot】u-boot支持的文件系统
  • 杭州职工业能力建设网站青岛seo全网营销
  • 哪家公司网站建设好点wordpress下载主题模板
  • 【强化学习】RLMT强制 CoT提升训练效果
  • 左Shift键失灵解决办法
  • 如何确定网站建设空间wordpress安装到本地
  • 建设网站使用的工具wordpress single模板
  • 网站域名注册费用哔哩哔哩网页入口
  • 承德市外贸网站建设网站如何建设推广
  • SVN 关于 ! 的解决
  • 如何优化自己的网站哪些建材网站可以做宣传
  • 黎平网站开发辽宁网站建设价格
  • dotnet-sdk-5.0.400-linux-x64.tar.gz 安装教程(Linux 手动安装 .NET 5.0.400 SDK 步骤)
  • 中医基础知识和核心知识
  • 校园文化宣传主题网站的建设唯美古风ppt模板
  • 珠海建网站的网络公司打开网站搜索
  • 上海营销型网站建设wap网站模板下载
  • 数字货币:从“虚拟金库”到法定货币的进化
  • 做博物馆网站最重要性企业网站营销案例
  • 企业网络搭建案例seo排名优化价格
  • 输入n个整数,输出其中最小的k个
  • 广州市增城区建设局网站是什么赣州市经开区住房和建设局网站
  • 网站导航条设计苏州网站建设渠道
  • 做网上夫妻去哪个网站如何分析竞争对手网站
  • 金华自助建站抖音免费推广网站
  • php的网站怎么做的成都区块链网站开发
  • 深圳网站建设专家网站怎么集成支付宝
  • 免费建手机网站网站安全检测腾讯
  • 《 Linux 点滴漫谈: 三 》掌控终端:让 Shell 成为你的系统魔杖
  • LangGraph 记忆系统实战:反馈循环 + 动态 Prompt 让 AI 持续学习