pyqt5实现一个简易音乐播放器(升级到v2版本)

Posted Mculover666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pyqt5实现一个简易音乐播放器(升级到v2版本)相关的知识,希望对你有一定的参考价值。

前言

假期最后一天,看到一篇文章使用pyqt实现了一个音乐播放器,刚好前段时间学完pyqt,来撸一个玩一玩,最终的效果如下:

后来又萌生想法,升级了一下UI:

本代码开源仓库:https://github.com/Mculover666/MP3Player

一、安装pyqt5

新建虚拟环境:

python -m venv venv

激活虚拟环境,安装pyqt5:

pip install pyqt5

二、类设计

MP3音乐播放器的所有内容都设计为MP3Player类,所以main.c文件中的内容变的简单:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
 
"""
MP3 player
 
author: Mculover666
version: v1.0.0
"""
 
import sys
from MP3Player import MP3Player
from PyQt5.QtWidgets import (QApplication)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = MP3Player()
    sys.exit(app.exec_())

MP3Player类的文件为:MP3Player.py

from PyQt5.QtWidgets import (QWidget, QDesktopWidget,
    QMessageBox, QHBoxLayout, QVBoxLayout, QSlider, QListWidget,
    QPushButton, QLabel, QComboBox)
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt

class MP3Player(QWidget):
    def __init__(self):
        super().__init__()

        #add your code here

        self.initUI()

    def initUI(self):
        self.resize(600, 400)
        self.center()
        self.setWindowTitle('MP3 player')   
        self.setWindowIcon(QIcon('resource/music.png'))
        self.show()
        
    # bring the window to the center of the screen    
    def center(self):
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

图标文件从iconfont下载,放在resource文件夹下,文件名为music.png:

此时运行main.py,可以看到窗口和图标:

三、界面设计

def __init__(self):
    super().__init__()

    self.startTimeLabel = QLabel('00:00')
    self.endTimeLabel = QLabel('00:00')
    self.slider = QSlider(Qt.Horizontal, self)
    self.playBtn = QPushButton('播放', self)
    self.prevBtn = QPushButton('上一曲', self)
    self.nextBtn = QPushButton('下一曲', self)
    self.openBtn = QPushButton('打开文件夹', self)
    self.musicList = QListWidget()
    self.modeCom = QComboBox()
    self.modeCom.addItem('顺序播放')
    self.modeCom.addItem('单曲循环')
    self.modeCom.addItem('随机播放')
    self.authorLabel = QLabel('Mculover666')
    self.textLable = QLabel('星光不问赶路人,时光不负有心人')
    self.versionLabel = QLabel('v1.0.0')

    self.hBoxSlider = QHBoxLayout()
    self.hBoxSlider.addWidget(self.startTimeLabel)
    self.hBoxSlider.addWidget(self.slider)
    self.hBoxSlider.addWidget(self.endTimeLabel)

    self.hBoxButton = QHBoxLayout()
    self.hBoxButton.addWidget(self.playBtn)
    self.hBoxButton.addWidget(self.nextBtn)
    self.hBoxButton.addWidget(self.prevBtn)
    self.hBoxButton.addWidget(self.modeCom)
    self.hBoxButton.addWidget(self.openBtn)

    self.vBoxControl = QVBoxLayout()
    self.vBoxControl.addLayout(self.hBoxSlider)
    self.vBoxControl.addLayout(self.hBoxButton)
        
    self.hBoxAbout = QHBoxLayout()
    self.hBoxAbout.addWidget(self.authorLabel)
    self.hBoxAbout.addStretch(1)
    self.hBoxAbout.addWidget(self.textLable)
    self.hBoxAbout.addStretch(1)
    self.hBoxAbout.addWidget(self.versionLabel)

    self.vboxMain = QVBoxLayout()
    self.vboxMain.addWidget(self.musicList)
    self.vboxMain.addLayout(self.vBoxControl)
    self.vboxMain.addLayout(self.hBoxAbout)
    
    self.setLayout(self.vboxMain)

    self.initUI()

设计的界面如下图:

四、实现功能

1. 打开文件夹添加音乐功能

引入 QFileDialog 类:

from PyQt5.QtWidgets import (QWidget, QDesktopWidget,
    QMessageBox, QHBoxLayout, QVBoxLayout, QSlider, QListWidget,
    QPushButton, QLabel, QComboBox, QFileDialog)

添加支持音乐格式和音乐列表成员(在__init__函数中):

self.song_formats = ['mp3', 'm4a', 'flac', 'wav', 'ogg']
self.songs_list = []
self.cur_playing_song = ''
self.is_pause = True

编写读取文件夹和添加音乐列表功能的函数:

    # open floder
    def openMusicFloder(self):
        self.cur_path = QFileDialog.getExistingDirectory(self, "选取音乐文件夹", './')
        if self.cur_path:
            self.showMusicList()
            self.cur_playing_song = ''
            self.startTimeLabel.setText('00:00')
            self.endTimeLabel.setText('00:00')
            self.slider.setSliderPosition(0)
            self.is_pause = True
            self.playBtn.setText('播放')
    
    #show music list
    def showMusicList(self):
        self.musicList.clear()
        for song in os.listdir(self.cur_path):
            if song.split('.')[-1] in self.song_formats:
                self.songs_list.append([song, os.path.join(self.cur_path, song).replace('\\\\', '/')])
                self.musicList.addItem(song)
        self.musicList.setCurrentRow(0)
        if self.songs_list:
                self.cur_playing_song = self.songs_list[self.musicList.currentRow()][-1]

设置打开按钮的回调函数:

self.openBtn.clicked.connect(self.openMusicFloder)

提前下载放到文件夹中:
运行程序,选择该文件夹,可以看到播放列表添加成功:

2. 播放音乐功能

引入 QMediaPlayer类,QMediaContent类,QUrl类:

from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent

添加用于实现播放/暂停功能的新成员:

self.player = QMediaPlayer()
self.is_switching = False

编写一个基于MessageBox的提示函数:

# 提示
def Tips(self, message):
    QMessageBox.about(self, "提示", message)

编写播放当前设置的音乐函数:

# 设置当前播放的音乐
def setCurPlaying(self):
    self.cur_playing_song = self.songs_list[self.musicList.currentRow()][-1]
    self.player.setMedia(QMediaContent(QUrl(self.cur_playing_song)))

编写播放/暂停函数:

    # 播放音乐
    def playMusic(self):
        if self.musicList.count() == 0:
                self.Tips('当前路径内无可播放的音乐文件')
                return
        if not self.player.isAudioAvailable():
                self.setCurPlaying()
        if self.is_pause or self.is_switching:
                self.player.play()
                self.is_pause = False
                self.playBtn.setText('暂停')
        elif (not self.is_pause) and (not self.is_switching):
                self.player.pause()
                self.is_pause = True
                self.playBtn.setText('播放')

最后设置播放按钮的回调函数:

self.playBtn.clicked.connect(self.playMusic)

此时已经可以正常的播放、暂停。

3. 歌曲切换功能

歌曲切换功能包括三个:

  • 上一曲
  • 下一曲
  • 双击音乐播放

编写上一曲和下一曲函数:

# 上一曲
def prevMusic(self):
    self.slider.setValue(0)
    if self.musicList.count() == 0:
        self.Tips('当前路径内无可播放的音乐文件')
        return
    pre_row = self.musicList.currentRow()-1 if self.musicList.currentRow() != 0 else self.musicList.count() - 1
    self.musicList.setCurrentRow(pre_row)
    self.is_switching = True
    self.setCurPlaying()
    self.playMusic()
    self.is_switching = False

# 下一曲
def nextMusic(self):
    self.slider.setValue(0)
    if self.musicList.count() == 0:
        self.Tips('当前路径内无可播放的音乐文件')
        return
    next_row = self.musicList.currentRow()+1 if self.musicList.currentRow() != self.musicList.count()-1 else 0
    self.musicList.setCurrentRow(next_row)
    self.is_switching = True
    self.setCurPlaying()
    self.playMusic()
    self.is_switching = False  

设置上一曲按钮和下一曲按钮的回调函数:

self.prevBtn.clicked.connect(self.prevMusic)
self.nextBtn.clicked.connect(self.nextMusic)

编写双击歌曲播放的函数:

# 双击歌曲名称播放音乐
def doubleClicked(self):
    self.slider.setValue(0)
    self.is_switching = True
    self.setCurPlaying()
    self.playMusic()
    self.is_switching = False

设置双击事件回调函数:

self.musicList.itemDoubleClicked.connect(self.doubleClicked)

4. 进度条

进度条需要每1s刷新一次,所以肯定需要用定时器来实现。

导入QTimer类:

from PyQt5.QtCore import Qt, QUrl, QTimer

引入 Time 类:

import os, time

首先编写设置进度条的函数:

    # 根据播放模式自动播放,并刷新进度条
    def playByMode(self):
        # 刷新进度条
        if (not self.is_pause) and (not self.is_switching):
            self.slider.setMinimum(0)
            self.slider.setMaximum(self.player.duration())
            self.slider.setValue(self.slider.value() + 1000)
        self.startTimeLabel.setText(time.strftime('%M:%S', time.localtime(self.player.position()/1000)))
        self.endTimeLabel.setText(time.strftime('%M:%S', time.localtime(self.player.duration()/1000)))
        # 顺序播放
        if (self.modeCom.currentIndex() == 0) and (not self.is_pause) and (not self.is_switching):
            if self.musicList.count() == 0:
                return
            if self.player.position() == self.player.duration():
                self.nextMusic()
        # 单曲循环
        elif (self.modeCom.currentIndex() == 1) and (not self.is_pause) and (not self.is_switching):
            if self.musicList.count() == 0:
                return
            if self.player.position() == self.player.duration():
                self.is_switching = True
                self.setCurPlaying()
                self.slider.setValue(0)
                self.playMusic()
                self.is_switching = False
        # 随机播放
        elif (self.modeCom.currentIndex() == 2) and (not self.is_pause) and (not self.is_switching):
            if self.musicList.count() == 0:
                return
            if self.player.position() == self.player.duration():
                self.is_switching = True
                self.musicList.setCurrentRow(random.randint(0, self.musicList.count()-1))
                self.setCurPlaying()
                self.slider.setValue(0)
                self.playMusic()
                self.is_switching = False

在初始化时设置定时器:

self.timer = QTimer(self)
self.timer.start(1000)
self.timer.timeout.connect(self.playByMode)

运行,可以看到进度条实时刷新。

接着还要实现反向功能,由进度条拖动控制播放进度,添加下面这行代码添加回调函数实现:

self.slider.sliderMoved[int].connect(lambda: self.player.setPosition(self.slider.value()))

5. 配置文件读写的实现

每次运行软件时,都要手动设置音乐文件夹的目录,非常麻烦,使用配置文件来实现记录配置的功能。

配置文件读写使用 configparser 模块实现。

导入该模块:

import configparser

添加配置文件名的成员:

self.settingfilename = 'config.ini'

5.1. 写配置文件的实现

编写记录配置的函数:

# 更新配置文件
def updateSetting(self):
	config = configparser.ConfigParser()
	config.read(self.settingfilename)
	if not os.path.isfile(self.settingfilename):
		config.add_section('MP3Player')
	config.set('MP3Player', 'PATH', self.cur_path)
	config.write(open(self.settingfilename, 'w'))

在用户选择完音乐文件夹之后调用:

# 打开文件夹
def openMusicFloder(self):
    self.cur_path = QFileDialog.getExistingDirectory(self, "选取音乐文件夹", './')
    if self.cur_path:
        self.showMusicList()
        self.cur_playing_song = ''
        self.startTimeLabel.setText('00:00')
        self.endTimeLabel.setText('00:00')
        self.slider.setSliderPosition(0)
        self.updateSetting()
        self.is_pause = True
        self.playBtn.setText('播放')

运行,选择音乐文件夹,软件创建的配置文件内容为:

5.2. 加载配置文件的实现

编写加载配置文件的函数:

# 加载配置文件
 def loadingSetting(self):
     config = configparser.ConfigParser()
     config.read(self.settingfilename)
     if not os.path.isfile(self.settingfilename):
         return
     self.cur_path = config.get('MP3Player', 'PATH')
     self.showMusicList()

在软件初始化阶段自动加载配置文件:

self.loadingSetting()

运行软件,可以看到自动加载出上次用户设置的目录。

6. 退出确认功能的实现

目前用户点击关闭按钮后,软件直接退出,接下来我们添加一个弹窗,确认用户是否要真的退出:

# 确认用户是否要真正退出
def closeEvent(self, event):
    reply = QMessageBox.question(self, 'M

以上是关于pyqt5实现一个简易音乐播放器(升级到v2版本)的主要内容,如果未能解决你的问题,请参考以下文章

做一个简易的音乐播放器

安卓第十七天笔记--简易版本音乐播放器

Android 简易音乐播放器

Python实现 ---简易在线音乐播放器

Android studio通过绑定式Service实现简易音乐播放器

利用js实现的音乐简易播放器