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, QAudioOutput
class MP3Player(QWidget):
def __init__(self):
super().__init__()
self.song_list = []
self.current_index = -1
self.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 = 0
if 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: # 确保时长大于0
current = 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 // 1000
minutes = seconds // 60
seconds = seconds % 60
return 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 re
def 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 = 0
self.pixmap = self.load_cover(song_path, default_cover)
if self.