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.pswp.cn/bicheng/80242.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/80242.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/80242.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[網安工具] 端口信息收集工具 —— 御劍高速 TCP 全端口掃描工具 · 使用手冊

&#x1f31f;想了解其它網安工具&#xff1f;看看這個&#xff1a;[網安工具] 網絡安全工具管理 —— 工具倉庫 管理手冊 https://github.com/NepoloHebo/Yujian-high-speed-TCP-full-port-scannerhttps://github.com/NepoloHebo/Yujian-high-speed-TCP-full-port-scanner 0…

數字孿生賦能智慧城市:從概念到落地的深度實踐

在城市規模與復雜度持續攀升的當下&#xff0c;傳統管理模式已難以滿足現代城市精細化治理需求。數字孿生技術憑借構建虛擬城市鏡像、實現實時數據交互與智能決策的特性&#xff0c;成為智慧城市建設的核心引擎。本文將通過多個典型案例&#xff0c;深度解析數字孿生技術如何重…

DeFi開發系統軟件開發:技術架構與生態重構

DeFi開發系統軟件開發&#xff1a;技術架構與生態重構 ——2025年去中心化金融開發的范式革新與實踐指南 一、技術架構演進&#xff1a;從單一鏈到多鏈混合引擎 現代DeFi系統開發已從單一公鏈架構轉向“跨鏈互操作混合模式”&#xff0c;結合中心化效率與去中心化安全雙重優勢…

相同IP和端口的服務器ssh連接時出現異常

起因 把服務器上的一個虛擬機搞壞了&#xff0c;所以刪除重新創建了一個&#xff0c;端口號和IP與之前的虛擬機相同。 ssh usernameIP -p port 時報錯 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! Someone…

驗證es啟動成功

1. 查看命令行輸出信息 在啟動 Elasticsearch 時&#xff0c;命令行窗口會輸出一系列日志信息。若啟動成功&#xff0c;日志里通常會有類似下面的信息&#xff1a; plaintext [2025-05-06T13:20:00,000][INFO ][o.e.n.Node ] [node_name] started其中 [node_na…

CentOS網絡之network和NetworkManager深度解析

文章目錄 CentOS網絡之network和NetworkManager深度解析1. CentOS網絡服務發展歷史1.1 傳統network階段&#xff08;CentOS 5-6&#xff09;1.2 過渡期&#xff08;CentOS 7&#xff09;1.3 新時代&#xff08;CentOS 8&#xff09; 2. network和NetworkManager的核心區別3. ne…

Unity:父掛 Rigidbody2D、子掛 Collider2D 時觸發器不生效的問題分析

目錄 ?問題現象 &#x1f50d; 排查與定位 ?? Unity 觸發機制的核心要求 ? 為什么把 Collider2D 移到父物體后就能觸發&#xff1f; &#x1f4a1; 解決方案 在 Unity 2D 游戲開發中&#xff0c;很多人習慣用父物體掛載 Rigidbody2D&#xff0c;而將不同的身體部位&am…

Google AI版圖:解析AI Studio, Gemini, NotebookLM與GCP

1. 2C vs 2B: AI Studio: 主要是面向開發者&#xff0c;提供一個易用的界面來探索和構建基于Google模型的應用。雖然最終的應用可能服務于C端或B端&#xff0c;但AI Studio本身更多是一個開發者的工具平臺&#xff0c;可以看作是連接模型能力和各種應用的橋梁。它可以被個人開…

Oracle EBS AP發票被預付款核算創建會計科目時間超長

背景 由于客戶職能部門的水電、通信和物業等等費用統一管理或對接部門報銷費,在報銷費的時候,用戶把所有費用分攤到各個末級部門,形成AP發票行有上千行, 問題癥狀 1、用戶過賬時,請求創建會計科目一直執行20多個小時未完成,只能手工強行取消請求。 2、取消請求以后,從后…

MySQL中MVCC指什么?

簡要回答&#xff1a; MVCC&#xff08;multi version concurrency control&#xff09;即多版本并發控制&#xff0c;為了確保多線程下數據的安全&#xff0c;可以通過undo log和ReadView來實現不同的事務隔離級別。 對于已提交讀和可重復讀隔離級別的事務來說&#xff0c;M…

賽季7靶場 -- Checker --User flag

本系列僅說明靶場的攻擊思路&#xff0c;不會給出任何的詳細代碼執行步驟&#xff0c;因為個人覺得找到合適的工具以實現攻擊思路的能力也非常重要。root要逆向&#xff0c;沒做了&#xff0c;但是user flag也有借鑒意義&#xff0c;關于2FA的繞過我們有必要了解 1.首先Nmap掃描…

【RAG技術全景解讀】從原理到工業級應用實踐

目錄 &#x1f31f; 前言&#x1f3d7;? 技術背景與價值&#x1f6a8; 當前技術痛點&#x1f6e0;? 解決方案概述&#x1f465; 目標讀者說明 &#x1f50d; 一、技術原理剖析&#x1f4d0; 核心概念圖解&#x1f4a1; 核心作用講解?? 關鍵技術模塊說明?? 技術選型對比 &…

【嵌入式開發-RS-485】

嵌入式開發-RS-485 ■ RS-485 連接方式■ RS-485 半雙工通訊■ RS-485 的特點■ UART硬流控■ RS-4851. 全雙工、半雙工接線2. 拓撲結構3. RS-485收發器3.1 發送模式&#xff08;TX&#xff09;3.2 接收模式&#xff08;RX&#xff09; 4. RS-485數據鏈路5. RS-485常用電路6. C…

[硬件電路-18]:MCU - LPC1765FBD100是恩智浦(NXP)半導體推出的一款基于ARM Cortex-M3內核的高性能32位微控制器

LPC1765FBD100是恩智浦&#xff08;NXP&#xff09;半導體推出的一款基于ARM Cortex-M3內核的高性能32位微控制器&#xff0c;具備高集成度、低功耗、豐富的外設接口和強大的處理能力&#xff0c;適用于工業控制、消費電子、醫療設備、通信系統等嵌入式應用場景。 以下從核心特…

MyBatis(進階)(xml標簽)

本節?標 1. 學習MyBatis的動態SQL查詢 2. 掌握MyBatis在項?中的應?, 可以使?Spring MVC完成?些基礎的功能 1. 動態SQL&#xff08;XML&#xff09; 動態 SQL 是Mybatis的強?特性之?&#xff0c;能夠完成不同條件下不同的 sql 拼接 可以參考官??檔&#xff1a; M…

QT QList容器及行高亮

總結QList是一個泛型/模板鏈表&#xff0c;可以自己定義數據類型&#xff0c;ExtraSelection是一種“數據類型”

【Python】Python項目中的依賴與配置:requirements.txt、setup.py、pyproject.toml 詳解

在昨天的文章【Python】通過Editable Install模式詳解&#xff0c;解決Python開發總是import出錯的問題 中&#xff0c; 我們提到了Python項目的配置文件requirements.txt、setup.py、pyproject.toml。在昨天的解決方案中&#xff0c; 我們同時維護了這三個文件。 由同學就問&a…

詳細聊聊 Synchronized,以及鎖的升級過程

在Java中&#xff0c;synchronized關鍵字是用于實現線程同步的重要機制&#xff0c;它通過內置鎖&#xff08;Monitor&#xff09;確保多個線程對共享資源的安全訪問。 1. synchronized 的基本使用與實現原理 使用方式 修飾實例方法&#xff1a;鎖是當前對象實例。public syn…

vue3的深入組件-組件 v-model

組件 v-model 基本用法? v-model 可以在組件上使用以實現雙向綁定。 從 Vue 3.4 開始&#xff0c;推薦的實現方式是使用 defineModel() 宏&#xff1a; <script setup> const model defineModel()function update() {model.value } </script><template>…

15.thinkphp的上傳功能

一&#xff0e;上傳功能 1. 如果要實現上傳功能&#xff0c;首先需要建立一個上傳表單&#xff0c;具體如下&#xff1a; <form action"http://localhost/tp6/public/upload"enctype"multipart/form-data" method"post"><input type&…