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

python实现的音乐播放器

python实现的音乐播放器

音乐播放器,原来写过一个简陋的例子,可见
https://blog.csdn.net/cnds123/article/details/137874107

那个不能拖动播放进度条上的滑块到新的位置播放。下面介绍的可以拖动播放进度条上的滑块到新的位置播放

简单实用的音乐播放器

这个简单实用的音乐播放器,运行界面:

需要安装,PyQt6这个第三方库。 

源码如下:

import sys
import os
from PyQt6.QtWidgets import (QApplication, QWidget, QLabel, QPushButton, QSlider, QHBoxLayout, QVBoxLayout, QFileDialog, QListWidget, QListWidgetItem
)
from PyQt6.QtCore import Qt, QTimer, QUrl
from PyQt6.QtGui import QPixmap, QPainter, QTransform, QPainterPath
from PyQt6.QtMultimedia import QMediaPlayer, QAudioOutputclass MP3Player(QWidget):def __init__(self):super().__init__()self.song_list = []self.current_index = -1self.init_ui()self.setup_player()def init_ui(self):self.setWindowTitle("音乐播放器 V1.0.2")self.setGeometry(300, 300, 600, 400)# 控件初始化self.playlist = QListWidget()self.playlist.itemDoubleClicked.connect(self.play_selected)self.play_btn = QPushButton("▶")self.prev_btn = QPushButton("⏮")self.next_btn = QPushButton("⏭")self.stop_btn = QPushButton("⏹")self.slider = QSlider(Qt.Orientation.Horizontal)self.time_label = QLabel("00:00 / 00:00")# 按钮样式btn_style = """QPushButton {font-size: 20px;min-width: 40px;min-height: 40px;border-radius: 20px;background: #666;color: white;}QPushButton:hover { background: #09f; }"""for btn in [self.play_btn, self.prev_btn, self.next_btn, self.stop_btn]:btn.setStyleSheet(btn_style)# 布局control_layout = QHBoxLayout()control_layout.addWidget(self.prev_btn)control_layout.addWidget(self.play_btn)control_layout.addWidget(self.next_btn)control_layout.addWidget(self.stop_btn)main_layout = QVBoxLayout()main_layout.addWidget(self.playlist)main_layout.addWidget(self.slider)main_layout.addWidget(self.time_label)main_layout.addLayout(control_layout)# 功能按钮buttons_layout = QHBoxLayout()# 添加文件按钮add_file_btn = QPushButton("添加文件")add_file_btn.clicked.connect(self.add_files)buttons_layout.addWidget(add_file_btn)# 删除文件按钮delete_file_btn = QPushButton("删除文件")delete_file_btn.clicked.connect(self.delete_file)buttons_layout.addWidget(delete_file_btn)# 帮助按钮help_btn = QPushButton("帮助")help_btn.clicked.connect(self.show_help)buttons_layout.addWidget(help_btn)main_layout.addLayout(buttons_layout)# 添加音量控制self.volume_slider = QSlider(Qt.Orientation.Horizontal)self.volume_slider.setRange(0, 100)self.volume_slider.setValue(70)  # 默认音量70%self.volume_slider.valueChanged.connect(self.change_volume)volume_layout = QHBoxLayout()volume_layout.addWidget(QLabel("音量:"))volume_layout.addWidget(self.volume_slider)main_layout.addLayout(volume_layout)self.setLayout(main_layout)# 连接信号self.play_btn.clicked.connect(self.toggle_play)self.prev_btn.clicked.connect(self.play_prev)self.next_btn.clicked.connect(self.play_next)self.stop_btn.clicked.connect(self.stop)self.slider.sliderMoved.connect(self.seek_position)def delete_file(self):# 获取当前选中的项目current_items = self.playlist.selectedItems()if not current_items:return# 逐一删除所选项目for item in current_items:index = self.playlist.row(item)# 如果删除的是正在播放的歌曲,先停止播放if index == self.current_index:self.player.stop()self.current_index = -1# 从列表和界面中删除项目self.playlist.takeItem(index)self.song_list.pop(index)# 如果正在播放的歌曲在被删除的歌曲之后,需要调整索引if index < self.current_index:self.current_index -= 1# 如果删除后列表为空,重置界面if not self.song_list:self.time_label.setText("00:00 / 00:00")self.slider.setValue(0)self.update_play_button(QMediaPlayer.PlaybackState.StoppedState)def show_help(self):# 创建帮助消息help_text = """<h3>音乐播放器使用帮助</h3><p><b>播放控制:</b></p><ul><li>播放/暂停:点击 ▶/⏸ 按钮</li><li>上一首:点击 ⏮ 按钮</li><li>下一首:点击 ⏭ 按钮</li><li>停止:点击 ⏹ 按钮</li></ul><p><b>播放列表:</b></p><ul><li>添加文件:点击"添加文件"按钮</li><li>删除文件:选择文件后点击"删除文件"按钮</li><li>播放指定歌曲:双击列表中的歌曲</li></ul><p><b>其他控制:</b></p><ul><li>调整进度:拖动进度条</li><li>调整音量:拖动音量滑块</li></ul>"""# 导入需要的组件from PyQt6.QtWidgets import QMessageBox# 显示帮助对话框help_dialog = QMessageBox(self)help_dialog.setWindowTitle("帮助")help_dialog.setTextFormat(Qt.TextFormat.RichText)help_dialog.setText(help_text)help_dialog.setIcon(QMessageBox.Icon.Information)help_dialog.exec()def change_volume(self, value):self.audio_output.setVolume(value / 100.0)def setup_player(self):self.player = QMediaPlayer()self.audio_output = QAudioOutput()self.audio_output.setVolume(0.7)  # 默认音量设置self.player.setAudioOutput(self.audio_output)# 定时器更新进度self.timer = QTimer()self.timer.timeout.connect(self.update_progress)self.timer.start(1000)# 播放状态变化self.player.playbackStateChanged.connect(self.update_play_button)# 添加媒体结束时的信号连接self.player.mediaStatusChanged.connect(self.handle_media_status_change)# 添加媒体时长变化的信号连接self.player.durationChanged.connect(self.duration_changed)self.player.errorOccurred.connect(self.handle_error)##    def handle_media_status_change(self, status):
##        # 使用 QTimer.singleShot 来避免潜在的递归调用或信号冲突
##        if status == QMediaPlayer.MediaStatus.EndOfMedia:
##            QTimer.singleShot(10, self.play_next)def handle_media_status_change(self, status):# 仅当媒体结束且不是暂停状态时处理if status == QMediaPlayer.MediaStatus.EndOfMedia:# 检查是否只有一首歌曲if len(self.song_list) == 1:# 只有一首歌曲时,重置到开始位置而不是尝试播放"下一首"self.player.setPosition(0)self.player.stop()self.update_play_button(QMediaPlayer.PlaybackState.StoppedState)# 重新播放if self.player.position() >= self.player.duration() - 100 and self.player.duration() > 0:self.player.setPosition(0)self.player.play()else:# 多首歌曲时,播放下一首QTimer.singleShot(10, self.play_next)def add_files(self):files, _ = QFileDialog.getOpenFileNames(self, "选择音频文件", "", "音频文件 (*.mp3 *.wav *.flac)")for file in files:if file not in self.song_list:self.song_list.append(file)self.playlist.addItem(os.path.basename(file))def play_selected(self, item):self.current_index = self.playlist.row(item)self.play()def duration_changed(self, duration):self.slider.setRange(0, duration)def handle_error(self, error, error_string):print(f"播放器错误: {error_string}")def play(self):if self.current_index < 0 and self.song_list:self.current_index = 0if 0 <= self.current_index < len(self.song_list):# 高亮当前播放的歌曲self.playlist.setCurrentRow(self.current_index)try:file = self.song_list[self.current_index]self.player.setSource(QUrl.fromLocalFile(file))self.player.play()except Exception as e:print(f"播放错误: {e}")def toggle_play(self):if self.player.isPlaying():self.player.pause()else:if self.player.position() == self.player.duration():self.play()else:self.player.play()def update_play_button(self, state):if state == QMediaPlayer.PlaybackState.PlayingState:self.play_btn.setText("⏸")else:self.play_btn.setText("▶")def update_progress(self):duration = self.player.duration()if duration > 0:  # 确保时长大于0current = self.player.position()self.slider.setValue(int(current))self.time_label.setText(f"{self.format_time(current)} / {self.format_time(duration)}")def seek_position(self, position):self.player.setPosition(position)def play_prev(self):if self.song_list:self.current_index = (self.current_index - 1) % len(self.song_list)self.play()def play_next(self):if not self.song_list:return# 先停止当前播放self.player.stop()# 然后切换到下一首self.current_index = (self.current_index + 1) % len(self.song_list)# 使用短延迟来确保状态已正确更新QTimer.singleShot(50, self.play)def stop(self):self.player.stop()self.slider.setValue(0)self.time_label.setText("00:00 / 00:00")def format_time(self, ms):seconds = ms // 1000minutes = seconds // 60seconds = seconds % 60return f"{minutes:02d}:{seconds:02d}"if __name__ == "__main__":app = QApplication(sys.argv)player = MP3Player()player.show()sys.exit(app.exec())

专业级别的音乐播放器

下面这个音乐播放器,源码来源于网络,适当修改,转载记录于此。

需要安装PyQt6、python-vlc、mutagen 这3个第三方库。

需要安装 VLC 播放器(python-vlc 是 VLC 的 Python 绑定,需依赖系统安装的 VLC),访问 VLC 官网Official download of VLC media player, the best Open Source player - VideoLAN ,下载并安装对应系统的版本。否则 程序运行时提示 vlc.dll not found。


运行效果:

源码如下:

import sys
import os
from PyQt6.QtWidgets import (QApplication, QWidget, QLabel, QPushButton, QSlider, QHBoxLayout, QVBoxLayout, QGridLayout, QFileDialog, QListWidget, QListWidgetItem, QMenu
)
from PyQt6.QtCore import Qt, QTimer, QUrl, QByteArray, pyqtSignal
from PyQt6.QtGui import QPixmap, QPainter, QTransform, QPainterPath, QFont, QColor, QLinearGradient, QBrush, QPen, QCursor, QScreen
from mutagen.mp3 import MP3
from mutagen.id3 import ID3, APIC
from PyQt6.QtMultimedia import QMediaPlayer, QAudioOutput
import vlc
import redef resource_path(relative_path):if hasattr(sys, '_MEIPASS'):return os.path.join(sys._MEIPASS, relative_path)return os.path.join(os.path.abspath("."), relative_path)# 旋转封面控件
class RotatingCover(QLabel):def __init__(self, song_path, default_cover="fm.png"):super().__init__()self.angle = 0self.pixmap = self.load_cover(song_path, default_cover)if self.
http://www.xdnf.cn/news/4791.html

相关文章:

  • 企业生产安全管理平台的功能架构
  • Java后端程序员学习前端之JavaScript
  • PHP反序列化漏洞
  • CBO和HBO区别及介绍
  • 【包含例题P1955、P1892、P2024、P1196】并查集、扩展域并查集、带权并查集
  • arcmap栅格数据地理坐标转换,从WGS84坐标到2000
  • 深入理解Bitmap及Roaring Map:原理与应用详解
  • PPIO × GPT4All:构建本地知识库,让AI更懂你
  • 从单智到多智:深度拆解基于MetaGPT的智能体辩论
  • AI原生手机:三大技术阵营的终极对决与未来展望
  • 使用Maple Flow创建电路最坏情况分析WCCA工作表
  • 【前端】每日一道面试题2:解释CSS盒模型的box-sizing属性,以及它在响应式布局中的作用。
  • 字符串哈希(算法题)
  • VR 南锣鼓巷:古老街区的数字化绘卷与沉浸式遨游​
  • 高处安装、维护拆除作业考试重点知识
  • PlatformIO
  • 遗传算法求解异构车队VRPTW问题
  • 基于Credit的流量控制
  • SQL知识点总结
  • 【Yolo精读+实践+魔改系列】Yolov3论文超详细精讲(翻译+笔记)
  • 第一次被AI指点出文章的问题
  • 【AXI总线专题】-AXI-LITE总线解读
  • 307.重新格式化电话号码
  • MySQL中MVCC的实现原理
  • WarpDemuX
  • AI开发跃迁指南(第三章:第四维度1——Milvus、weaviate、redis等向量数据库介绍及对比选型)
  • docker镜像误删恢复
  • 网络字节序 - 大端
  • 三格电子—ProfiNet 转 CAN/CANopen 网关应用案例
  • pygame联网飞机大战游戏实现