文章目錄
- 一.前言
- 二.項目簡介
- 三.詳細模塊介紹
- 1.主界面
- 2.歌單廣場
- 3.歌單詳情頁
- 4.歌手篩選
- 5.歌手詳情頁
- 6.專輯詳情頁
- 7.歌曲榜單頁
- 8.搜索結果頁
- 9.其他
- 1.托盤菜單
- 2.設置
- 四.核心問題回答
- 1.軟件UI效果實現
- 2.為什么我做不出來這么漂亮的界面?
- 3.旋轉黑膠效果怎么做出來的呀?
- 4.關于項目
- 1.項目結構
- 2.項目依賴
- 3.項目打包
- 五.總結
[更新于20250822],文件大小76.7 M,歡迎下載體驗!點擊下載
本次采用混合開發制作了一款高顏值的在線音樂播放器,內置多個功能頁面,非常適合學習!
拿到代碼的同學,請務必仔細閱讀本篇博客,避免踩坑!
本篇能幫您解決大量學習pyqt5過程中的問題,少走彎路!
一.前言
本次開發的音樂播放器項目名稱為:pyqt5-joy-music,這是一款使用混合語言開發的高顏值在線音樂播放器,博主參考了一款VUE風格的音樂播放器,使用html+pyqt5完成整個項目的開發!
二.項目簡介
博主使用一張思維導圖展示所有功能,大家可以自行放大查看。
三.詳細模塊介紹
1.主界面
主界面由頂部窗口控制、基本信息展示,中間為內容展示區、歌曲信息展示區域,底部為播放控制區域。
我們為了放置背景過度拉伸導致原圖失真,本次采用了svg圖像作為背景圖片,設計了多種(十款)純色、漸變色、紋理方案。
我們的播放器啟動后會自動加載上次播放的內容到播放列表,如果沒有播放歷史,則加載推薦歌曲到播放列表,用戶可以通過雙擊歌曲名稱的方式開始播放歌曲,音樂播放前會加載歌曲基本信息和歌詞數據到右側信息展示區域,我們采用動態的live標志和旋轉的專輯黑膠轉盤來標識當前在播音樂。
用戶可以將鼠標移動到歌曲上,會通過toolTip展示歌曲的詳細信息,用戶在歌曲上右擊鼠標,會展示詳細的歌曲操作菜單:播放歌曲、下載歌曲、播放列表操作:清空列表、移除當前,搜索相關:搜索歌曲名稱、搜索專輯、搜索歌手。
2.歌單廣場
這是主界面內容的另一個界面,主要是通過鼠標滾動在界面中篩選歌單,歌單內容展示邏輯為無限下拉,用戶可以在左側改變歌單排序規則,可選項為:最新、最熱。
3.歌單詳情頁
用戶可以點擊歌單封面上的播放按鈕開始播放歌單內容,點擊歌單名稱進入歌單詳情頁。
在這個頁面用戶能夠查看所選歌單的詳細信息,頁面內容包含基本信息展示以及歌曲列表,歌曲列表一頁展示30條,基本信息和歌曲列表是同步向下滾動的。
點擊播放按鈕,軟件開始從第一首歌曲開始播放,雙擊歌曲列表的歌曲,軟件從用戶選擇的歌曲開始播放,并且用播放列表替換正在播放
4.歌手篩選
在這個頁面用戶可以通過不同的條件對歌手進行篩選,我們內置了多個篩選條件,用戶可以采用極細的粒度進行篩選,篩選結果里的歌手支持無限下拉加載的,當下拉一定高度的時候,右下角會展示“回到頂部”的按鈕,用戶可以快速回到頂部更改篩選項。
5.歌手詳情頁
我們為每位歌手設計了漂亮的歌手詳情頁,在這個頁面用戶能看到歌手的信息以及相關數據(單曲、專輯、相似歌手推薦以及用戶的詳細文字信息),用戶可以通過切換tab來查看不同維度的展示信息。
用戶可以點擊歌手基本信息下方的播放按鈕播放用戶歌曲、點擊分享按鈕會復制分享信息到用戶剪切板,用戶可以復制信息發給自己的好友!
用戶可以雙擊歌曲,軟件就會開始播放所選的指定歌曲
用戶可以點擊專輯封面開始播放所選專輯歌曲,點擊專輯名稱進入專輯詳情頁面
用戶點擊推薦的相似歌手封面播放按鈕,就開始播放選擇的歌手的歌曲,點擊相似歌手的名字,到所選歌手的二級頁
用戶點擊詳細信息tab,可以查看當前歌手的詳細文字信息
6.專輯詳情頁
您可以通過點擊專輯名字到專輯的二級頁,即專輯詳情頁,在這個頁面可以查看所選專輯的詳細信息以及歌曲數據,表格內歌曲數據是通過熱度降序排序,點擊播放按鈕,就開始從專輯第一首歌曲開始播放,點擊分享按鈕能夠分享專輯并復制分享文案到剪切板。
7.歌曲榜單頁
在這個頁面展示了不同類別的歌曲榜單,用戶可以點擊榜單封面的播放按鈕從第一首開始播放所選榜單的歌曲。
8.搜索結果頁
用戶在上方選擇“歌曲搜索”,點擊后打開搜索子窗口,您可以通過輸入關鍵字后點擊搜索按鈕(或者按下回車)對歌曲進行搜索,最后軟件跳轉到搜索結果頁展示歌曲的搜索結果。
9.其他
1.托盤菜單
我們的音樂播放器擁有和主流樣式一致的托盤菜單組件,軟件啟動后會自動注冊托盤菜單到屏幕右下角(windows),用戶可以將鼠標移入托盤菜單查看當前在播歌曲,亦可通過按下鼠標右鍵查看托盤菜單的詳細內容并操作音樂播放器,可以操作的內容包括:播放控制(上一曲、播放暫停、下一曲)、音量控制(靜音、詳細音量調節)、播放模式切換(單曲循環、隨機播放、列表循環)、打開設置以及退出軟件,這里值得一提的是當歌曲正在播放時,播放控制和音量調節之間展示了歌曲的名稱和歌手名,當這個信息超過了一定的寬度時,這段文字將會左右滾動,盡可能將全部的信息展示出來!
2.設置
我們的音樂播放器支持多種內容設置,并且能夠保存設置到本地配置文件,方便再次啟動后配置生效,具體的設置內容為:
開關類:
精簡tab模式:開啟此功能,界面只會展示“正在播放”和“歌曲搜索”
系統不休眠:開啟此功能,我們的電腦屏幕不會息屏,方便要聽歌但是又不操作屏幕的用戶
傳送門:這是作者的一個巧思,用戶可以在這里選擇要傳送到的頁面,可以選擇歌單、歌手、專輯
重置背景:將軟件背景還原到默認的背景圖
清空緩存:我們采用了cache的方式緩存了一些圖片數據,目的是加速音樂播放(主要是圖片),清空之后會減少本地磁盤占用,但是下次播放音樂會重新加載圖片
關于作者:點擊之后會彈出詢問對話框,用戶選擇了Yes之后打開博主的CSDN博客
關于軟件:點擊之后會彈出一段文案,告知用戶本軟件相關信息
更換背景:我們使用分割線將開關和背景選擇區域分割開來,在下方設有垂直滾動區域,里面羅列了幾種不同顏色、紋理風格的背景圖,用戶通過點擊對應的背景圖來改變背景效果,設置是實時生效的
這個頁面的所有對話框都是有二次確認的,每個彈出的對話框都是同樣的風格,窗口彈出時,背景效果為高斯模糊效果。
四.核心問題回答
1.軟件UI效果實現
經常會有朋友私聊我,和博主詢問.ui文件,這里統一回答:沒有UI文件,軟件上的所有pyqt組件都是手搓的自定義組件,本次軟件的一些位置采用了html語言,這樣可以更加高度自定義展示內容,讓我們的軟件整體軟件更加高顏值!
我們使用pyqt5+html+不依賴外部html文件的方式渲染展示組件,使用QWebChannel進行js和python之間的數據交互,實現了數據和組件的雙向綁定。
我們定義了NoContextMenuWebEngineView組件,能夠幫我們阻塞頁面的右擊菜單,采用NoRightClickWebEnginePage阻塞掉所有右擊事件,更能讓我們隱藏html瀏覽器效果,實現了“以html元素替代QWidget組件”。
2.為什么我做不出來這么漂亮的界面?
這里我想說:一個好看實用的作品一定是有參考的,當然也包括作者的奇思妙想,這里博主參考了VUE版本的音樂播放器樣式(https://blog.hzyo.cn/music/),這位博主做的界面相當漂亮,給人一種很干凈清爽的感覺,唯一覺得不足的地方是頁面太少了,為此,博主在現有基礎上進行開發、完善,加入了多個頁面以及子頁面,真正實現了一個高顏值且實用的音樂播放器,最后再次感謝!
3.旋轉黑膠效果怎么做出來的呀?
這個組件采用重寫QLabel的paintEvent函數實現黑膠、唱片針的展示,采用圓形效果展示專輯封面,值得一提的是,我們采用了緩存的方式加載歌曲專輯封面,也就是說,越是播放過的歌曲,加載封面越快,二次加載相當于讀取本地文件,無網絡訪問請求,就是因為用了這些緩存的思想,加速了軟件的速度。
下面是黑膠轉盤組件的源代碼:
class AlbumWidget(QLabel):"""更像唱片的旋轉 QLabel"""def __init__(self, parent=None):super().__init__(parent)self.param_init()self.timer_init()self.ui_init()def param_init(self):self._angle = 0self.label_width = 170self.extra = 20 # 額外的寬高self._pix = QPixmap()self.side_ratio = 0.65 # 專輯封面面積占比self.default_cover = style_conf.default_album_coverself.light_circle_color = QColor(255, 255, 255) # 黑膠外圈顏色self.center_dot_color = QColor(220, 220, 220) # 中心點顏色self.setAttribute(Qt.WA_TranslucentBackground)def ui_init(self):self.setFixedSize(self.label_width + self.extra, self.label_width + self.extra)self.set_album_pic(self.default_cover)def timer_init(self):self.rotate_timer = QTimer(self)self.rotate_timer.timeout.connect(self.rotate)self.rotate_timer.setInterval(system_conf.album_rotate_timer_interval)def set_album_pic(self, album_pic):"""設置專輯封面圖片:param album_pic::return:"""def set_pic(pix):if not pix:returnelif not isinstance(pix, QPixmap):pix = QPixmap(pix)self._pix = pix.scaled(int(self.label_width * self.side_ratio),int(self.label_width * self.side_ratio),Qt.KeepAspectRatio, Qt.SmoothTransformation)self._pix = rounded_pixmap(self._pix, int(self._pix.width() / 2))self.update()self.control_rotate_state(True)if not album_pic:returnif album_pic.startswith(":"): # 本地資源set_pic(album_pic)else: # 網絡圖self.thread = subThread(subThread.get_web_pix, album_pic, byte_data=True)self.thread.pixmap_finished.connect(lambda pix: set_pic(pix))self.thread.start()self._angle = 0def control_rotate_state(self, state):"""設置旋轉狀態:param state::return:"""if state:if not self.rotate_timer.isActive():self.rotate_timer.start()else:if self.rotate_timer.isActive():self.rotate_timer.stop()def rotate(self):"""專輯封面旋轉:return:"""self._angle = (self._angle + 1) % 360self.update()def paintEvent(self, event):painter = QPainter(self)painter.setRenderHint(QPainter.Antialiasing)painter.setRenderHint(QPainter.SmoothPixmapTransform)center = QPointF(self.width() / 2, self.height() / 2)radius = self.label_width / 2# 0. 繪制白色發光外圈glow_radius = radius + 10 # 比唱片略大gradient = QRadialGradient(center, glow_radius)glow_radius = radius + 35 # 發光范圍更大color = self.light_circle_colorgradient.setColorAt(0.0, QColor(color.red(), color.green(), color.blue(), 180))gradient.setColorAt(0.6, QColor(color.red(), color.green(), color.blue(), 80))gradient.setColorAt(1.0, QColor(color.red(), color.green(), color.blue(), 0))painter.setBrush(gradient)painter.setPen(Qt.NoPen)painter.drawEllipse(center, glow_radius, glow_radius)# 1. 繪制黑膠外圈painter.setBrush(QColor(30, 30, 30))painter.setPen(Qt.NoPen)painter.drawEllipse(center, radius, radius)# 1.1 繪制灰色磁道(只在外圈區域)painter.save()painter.translate(center)track_pen = QPen(QColor(80, 80, 80)) # 灰色磁道track_pen.setWidth(1)painter.setPen(track_pen)track_count = 15 # 磁道條數inner_radius = radius * 0.7 # 磁道起始半徑,避免覆蓋中間封面for i in range(track_count):r = inner_radius + (radius - inner_radius) * (i / track_count)painter.drawEllipse(QPointF(0, 0), r, r)painter.restore()# 2. 平移 + 旋轉畫布(用于繪制封面圖)painter.translate(center)painter.rotate(self._angle)# 3. 繪制中間封面圖(略小)pix_w = self._pix.width()pix_h = self._pix.height()painter.drawPixmap(-pix_w / 2, -pix_h / 2, self._pix)# 4. 恢復角度painter.rotate(-self._angle)painter.translate(-center)# 5. 繪制中心小圓點(軸心)center_dot_radius = 5painter.setBrush(self.center_dot_color)painter.setPen(Qt.NoPen)painter.drawEllipse(center, center_dot_radius, center_dot_radius)painter.end()
4.關于項目
我們的項目為私有項目,項目名稱wieldpyqt5-joy-music,項目開發周期為20天,主要耗時的地方是設計樣式,好在問題都解決了。
1.項目結構
下圖為項目代碼結構,整體代碼量為9000行,主要代碼量由unique_widgets.py產生,約6.5K,這里為主要的頁面代碼,包含webengine和html
main_page.py為主要的邏輯調度,所有的組件都被它調度起來,把我們整個系統串聯
threads/目錄是核心線程,采用多線程可以避免不必要的卡頓,加速音樂播放器軟件執行效率
engine/目錄是核心引擎,所有的網絡內容操作都在這里進行,配合核心線程完成網絡數據的獲取
conf/目錄是主要的配置目錄,這里面包含樣式、系統內容、測試數據,這里面內容的修改直接影響軟件界面展示的內容
resource/目錄是主要的資源所在目錄,我們創建了bg_imgs/目錄用于存儲背景圖,創建了others/目錄用于存儲軟件圖標以及其他相關圖片資源內容
utils/是系統工具類和工具方法,都是博主常用的公共方法,每個方法在軟件中都有引用
2.項目依賴
大家拿到源代碼直接執行下面命令進行項目依賴的一鍵安裝:
pip install -r requirements.txt
本項目依賴相當干凈,博主貼在下方:
PyQt5==5.15.11
PyQt5_sip==12.15.0
QtAwesome==1.3.1
PyYAML==6.0.2
3.項目打包
關于項目打包本來筆者不抱有太大希望,因為我們采用的混合開發可能會有兼容問題,剛開始確實還有點擔心,但是第一次嘗試打包成功之后,博主更加堅定了這種開發方案的思路。
本次打包的安裝包大小為76.7M,大家下載下來安裝包,按照傻瓜式的下一步進行安裝即可,最后得到和博主同款好用高顏值的音樂播放器!
五.總結
本次和大家分享了我開發的高顏值音樂播放器-Joy音樂播放器,這款播放器包含多個頁面,滿足了我們日常的聽歌需求,在博客中和大家介紹了我進行“混合開發”的大致思路,為以后項目開發指明了方向,這套代碼適合有html基礎并且愿意學習pyqt技術的同學來學習,真的很值得一學!