PYcharm——pyqt音乐播放器

系统概述

使用python开发一个简单的音乐播放器,如果你也无聊不妨动手试一下。

建一个基于 PyQt 的音乐播放器,实现图片中展示的功能,包括播放控制、进度条、音量调节、播放列表等核心功能。

我们将使用 PyQt5 作为 GUI 框架,结合 PyQt5 的 QMediaPlayer 组件来实现音频播放功能。

这个音乐播放器实现了以下功能:

核心播放控制:播放、暂停、停止、上一首、下一首

进度条显示和控制:可以拖动进度条调整播放位置

音量调节功能

播放列表管理:添加音乐、删除音乐、清空列表

歌曲信息显示:当前播放歌曲名、播放时间

右键菜单支持:对播放列表项进行操作

使用方法:

点击 "添加音乐" 按钮选择本地音频文件(支持 mp3、wav、flac、m4a 等格式)

在播放列表中双击歌曲开始播放

使用控制按钮进行播放控制

可以拖动进度条调整播放位置

使用音量滑块调节音量大小

要在 PyCharm 中运行此程序,你需要先安装 PyQt5 和 PyQt5 多媒体模块:

程序已经设置了中文字体支持,可以正常显示中文。界面布局简洁直观,符合图片中展示的音乐播放器基本功能需求。你可以根据需要进一步美化界面或添加更多功能,如均衡器、歌词显示等。

软件介绍

python 复制代码
import sys
import os
from PyQt5.QtWidgets import (QApplication, QMainWindow, QPushButton, QSlider, 
                            QLabel, QListWidget, QFileDialog, QVBoxLayout, 
                            QHBoxLayout, QWidget, QStyle, QListWidgetItem,
                            QSplitter, QMenu, QAction, QMessageBox)
from PyQt5.QtCore import Qt, QUrl, QTimer, QPoint
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
from PyQt5.QtGui import QIcon, QPixmap, QFont

class MusicPlayer(QMainWindow):
    def __init__(self):
        super().__init__()
        
        # 设置中文字体支持
        font = QFont()
        font.setFamily("SimHei")
        self.setFont(font)
        
        # 初始化媒体播放器
        self.player = QMediaPlayer()
        self.player.durationChanged.connect(self.update_duration)
        self.player.positionChanged.connect(self.update_position)
        self.player.stateChanged.connect(self.update_state)
        
        # 当前播放列表索引
        self.current_index = -1
        self.playlist = []
        
        # 初始化UI
        self.init_ui()
        
    def init_ui(self):
        # 设置窗口标题和大小
        self.setWindowTitle("音乐播放器")
        self.setGeometry(300, 300, 800, 600)
        
        # 创建中心部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 主布局
        main_layout = QVBoxLayout(central_widget)
        
        # 专辑封面
        self.album_cover = QLabel()
        self.album_cover.setAlignment(Qt.AlignCenter)
        self.album_cover.setMinimumHeight(300)
        # 设置默认封面
        default_pixmap = QPixmap(300, 300)
        default_pixmap.fill(Qt.lightGray)
        self.album_cover.setPixmap(default_pixmap.scaled(
            self.album_cover.width(), self.album_cover.height(), 
            Qt.KeepAspectRatio, Qt.SmoothTransformation))
        
        main_layout.addWidget(self.album_cover)
        
        # 歌曲信息
        self.song_info = QLabel("准备就绪")
        self.song_info.setAlignment(Qt.AlignCenter)
        self.song_info.setStyleSheet("font-size: 16px; font-weight: bold;")
        main_layout.addWidget(self.song_info)
        
        # 进度条
        self.progress_layout = QHBoxLayout()
        
        self.time_label = QLabel("00:00")
        self.progress_layout.addWidget(self.time_label)
        
        self.progress_bar = QSlider(Qt.Horizontal)
        self.progress_bar.sliderMoved.connect(self.set_position)
        self.progress_layout.addWidget(self.progress_bar)
        
        self.total_time_label = QLabel("00:00")
        self.progress_layout.addWidget(self.total_time_label)
        
        main_layout.addLayout(self.progress_layout)
        
        # 控制按钮
        self.controls_layout = QHBoxLayout()
        
        self.prev_button = QPushButton()
        self.prev_button.setIcon(self.style().standardIcon(QStyle.SP_MediaSkipBackward))
        self.prev_button.clicked.connect(self.play_previous)
        self.controls_layout.addWidget(self.prev_button)
        
        self.play_button = QPushButton()
        self.play_button.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
        self.play_button.clicked.connect(self.toggle_play_pause)
        self.controls_layout.addWidget(self.play_button)
        
        self.stop_button = QPushButton()
        self.stop_button.setIcon(self.style().standardIcon(QStyle.SP_MediaStop))
        self.stop_button.clicked.connect(self.stop)
        self.controls_layout.addWidget(self.stop_button)
        
        self.next_button = QPushButton()
        self.next_button.setIcon(self.style().standardIcon(QStyle.SP_MediaSkipForward))
        self.next_button.clicked.connect(self.play_next)
        self.controls_layout.addWidget(self.next_button)
        
        self.controls_layout.addSpacing(20)
        
        # 音量控制
        self.volume_label = QLabel("音量:")
        self.controls_layout.addWidget(self.volume_label)
        
        self.volume_slider = QSlider(Qt.Horizontal)
        self.volume_slider.setMaximumWidth(100)
        self.volume_slider.setValue(70)
        self.player.setVolume(70)
        self.volume_slider.valueChanged.connect(self.set_volume)
        self.controls_layout.addWidget(self.volume_slider)
        
        main_layout.addLayout(self.controls_layout)
        
        # 分割器
        splitter = QSplitter(Qt.Vertical)
        
        # 播放列表
        self.playlist_label = QLabel("播放列表")
        self.playlist_label.setStyleSheet("font-size: 14px; font-weight: bold;")
        main_layout.addWidget(self.playlist_label)
        
        self.playlist_widget = QListWidget()
        self.playlist_widget.doubleClicked.connect(self.play_selected)
        # 右键菜单支持
        self.playlist_widget.setContextMenuPolicy(Qt.CustomContextMenu)
        self.playlist_widget.customContextMenuRequested.connect(self.show_context_menu)
        main_layout.addWidget(self.playlist_widget)
        
        # 底部按钮
        self.bottom_layout = QHBoxLayout()
        
        self.add_button = QPushButton("添加音乐")
        self.add_button.clicked.connect(self.add_music)
        self.bottom_layout.addWidget(self.add_button)
        
        self.clear_button = QPushButton("清空列表")
        self.clear_button.clicked.connect(self.clear_playlist)
        self.bottom_layout.addWidget(self.clear_button)
        
        main_layout.addLayout(self.bottom_layout)
        
        # 状态栏显示当前状态
        self.statusBar().showMessage("就绪")
        
        # 显示窗口
        self.show()
    
    def add_music(self):
        """添加音乐到播放列表"""
        files, _ = QFileDialog.getOpenFileNames(
            self, "选择音乐文件", "", "音频文件 (*.mp3 *.wav *.flac *.m4a)"
        )
        
        if files:
            for file in files:
                # 确保文件路径正确
                file_url = QUrl.fromLocalFile(file)
                # 获取文件名
                file_name = os.path.basename(file)
                
                # 添加到播放列表
                self.playlist.append((file_name, file_url))
                # 添加到列表控件
                self.playlist_widget.addItem(file_name)
                
            self.statusBar().showMessage(f"已添加 {len(files)} 首音乐")
            
            # 如果是第一个添加的音乐,自动选中
            if len(self.playlist) == len(files):
                self.playlist_widget.setCurrentRow(0)
                self.current_index = 0
    
    def play_selected(self):
        """播放选中的音乐"""
        selected_index = self.playlist_widget.currentRow()
        if selected_index >= 0 and selected_index < len(self.playlist):
            self.current_index = selected_index
            self.play_current()
    
    def play_current(self):
        """播放当前索引的音乐"""
        if 0 <= self.current_index < len(self.playlist):
            song_name, url = self.playlist[self.current_index]
            self.player.setMedia(QMediaContent(url))
            self.player.play()
            self.song_info.setText(f"正在播放: {song_name}")
            self.statusBar().showMessage(f"正在播放: {song_name}")
    
    def toggle_play_pause(self):
        """切换播放/暂停状态"""
        if self.player.state() == QMediaPlayer.PlayingState:
            self.player.pause()
        else:
            if self.player.mediaStatus() == QMediaPlayer.NoMedia and len(self.playlist) > 0:
                self.current_index = 0
                self.play_current()
            else:
                self.player.play()
    
    def stop(self):
        """停止播放"""
        self.player.stop()
        self.song_info.setText("已停止")
        self.statusBar().showMessage("已停止")
    
    def play_next(self):
        """播放下一首"""
        if len(self.playlist) == 0:
            return
            
        self.current_index = (self.current_index + 1) % len(self.playlist)
        self.playlist_widget.setCurrentRow(self.current_index)
        self.play_current()
    
    def play_previous(self):
        """播放上一首"""
        if len(self.playlist) == 0:
            return
            
        self.current_index = (self.current_index - 1) % len(self.playlist)
        self.playlist_widget.setCurrentRow(self.current_index)
        self.play_current()
    
    def set_volume(self, value):
        """设置音量"""
        self.player.setVolume(value)
        self.statusBar().showMessage(f"音量: {value}%")
    
    def update_duration(self, duration):
        """更新总时长显示"""
        self.progress_bar.setRange(0, duration)
        # 转换为分:秒格式
        total_seconds = duration // 1000
        minutes = total_seconds // 60
        seconds = total_seconds % 60
        self.total_time_label.setText(f"{minutes:02d}:{seconds:02d}")
    
    def update_position(self, position):
        """更新当前播放位置"""
        # 防止进度条更新时触发sliderMoved事件
        self.progress_bar.blockSignals(True)
        self.progress_bar.setValue(position)
        self.progress_bar.blockSignals(False)
        
        # 更新当前时间标签
        current_seconds = position // 1000
        minutes = current_seconds // 60
        seconds = current_seconds % 60
        self.time_label.setText(f"{minutes:02d}:{seconds:02d}")
        
        # 如果播放结束,自动播放下一首
        if position >= self.player.duration() and self.player.duration() > 0:
            self.play_next()
    
    def set_position(self, position):
        """设置播放位置"""
        self.player.setPosition(position)
    
    def update_state(self, state):
        """更新播放状态"""
        if state == QMediaPlayer.PlayingState:
            self.play_button.setIcon(self.style().standardIcon(QStyle.SP_MediaPause))
        else:
            self.play_button.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
    
    def clear_playlist(self):
        """清空播放列表"""
        self.stop()
        self.playlist.clear()
        self.playlist_widget.clear()
        self.current_index = -1
        self.song_info.setText("播放列表已清空")
        self.statusBar().showMessage("播放列表已清空")
    
    def show_context_menu(self, position):
        """显示右键菜单"""
        if not self.playlist_widget.selectedItems():
            return
            
        menu = QMenu()
        remove_action = QAction("移除选中项", self)
        remove_action.triggered.connect(self.remove_selected)
        
        play_action = QAction("播放选中项", self)
        play_action.triggered.connect(self.play_selected)
        
        menu.addAction(play_action)
        menu.addAction(remove_action)
        menu.exec_(self.playlist_widget.mapToGlobal(position))
    
    def remove_selected(self):
        """移除选中的项目"""
        selected_items = self.playlist_widget.selectedItems()
        if not selected_items:
            return
            
        # 获取选中项的索引
        indexes = [self.playlist_widget.row(item) for item in selected_items]
        # 按降序排序,从后往前删除
        indexes.sort(reverse=True)
        
        for index in indexes:
            # 如果删除的是当前播放的歌曲
            if index == self.current_index:
                self.stop()
                # 如果不是最后一首歌,播放下一首
                if index < len(self.playlist) - 1:
                    self.current_index = index
                else:
                    self.current_index = 0 if len(self.playlist) > 1 else -1
            
            # 从列表中删除
            del self.playlist[index]
            # 从控件中删除
            item = self.playlist_widget.takeItem(index)
            del item
        
        # 更新当前索引(如果删除了前面的项目)
        if self.current_index > 0 and self.current_index >= len(self.playlist):
            self.current_index = len(self.playlist) - 1
        
        self.statusBar().showMessage(f"已移除 {len(selected_items)} 首音乐")

if __name__ == "__main__":
    # 确保中文显示正常
    font = QFont("SimHei")
    
    app = QApplication(sys.argv)
    app.setFont(font)
    player = MusicPlayer()
    sys.exit(app.exec_())

示例演示

优化建议

相关推荐
QQ_19632884754 天前
Python-flask框架西山区家政服务评价系统网站设计与开发-Pycharm django
python·pycharm·flask
Diligently_4 天前
idea 中vm option 配置
java·ide·intellij-idea
我命由我123454 天前
在 Android Studio 中,新建 AIDL 文件按钮是灰色
android·ide·android studio·安卓·android jetpack·android-studio·android runtime
AC赳赳老秦4 天前
云原生AI故障排查新趋势:利用DeepSeek实现高效定位部署报错与性能瓶颈
ide·人工智能·python·云原生·prometheus·ai-native·deepseek
被制作时长两年半的个人练习生4 天前
claude code for vscode 配置 qwen3.5
ide·vscode·claude code·qwen3.5
圣心4 天前
Visual Studio Code 中的 AI 智能操作
ide·人工智能·vscode
吹牛不交税4 天前
关于vscode左侧资源管理器目录层级疑似异常的问题
ide·vscode·编辑器
xixi09244 天前
selenium IDE安装使用教程
ide·selenium·测试工具
西门吹-禅4 天前
【eclipse 升级】
java·ide·eclipse
code bean5 天前
Visual Studio 2026 离线安装包制作指南
ide·visual studio