使用QMediaPlayer播放音乐文件
1.QMediaPlayer类功能概述
QMediaPlayer可以播放经过压缩的音频或视频文件,如wav、mp3、wma、wmv、avi等文件,QMediaPlayer可以播放单个文件,也可以和QMediaPlaylist类结合,对一个播放列表进行播放。所以,使用QMediaPlayer和QMediaPlaylist可以轻松地设计一个自己的音乐或视频播放器。

QMediaPlayer的主要接口函数如表所示:

函数原型

功能描述

duration()

返回当前文件播放时间总长,单位ms返回当前文件播放时间总长,单位ms

setPosition(position)

设置当前文件播放位置,单位ms

setMuted(muted)

设置是否静音,muted为bool类型

isMuted()

bool型返回值表示是否静音,True表示静音

setPlaylist(playlist)

设置播放列表,playlist是QMediaPlaylist类型

playlist()

返回设置的播放列表,返回值为QMediaPlaylist类型

state()

返回播放器当前的状态,返回值是枚举类型QMediaPlayer.State

setVolume(volume)

设置播放音量,int型参数volume的值在0~100

setPlaybackRate(rate)

设置播放速度,float型参数rate默认为1,表示正常速度

setMedia(media)

设置播放媒体文件,参数media为QMediaContent类型

currentMedia()

返回当前播放的媒体文件,返回值为QMediaContent类型

play()

开始播放

pause()

暂停播放

stop()

停止播放

QMediaPlayer有几个有用的信号可以反映播放状态或文件信息。
(1)stateChanged(state)信号在调用play()、pause()、stop()函数时发射,反映播放器当前的状态。参数state是枚举类型QMediaPlayer.State,该枚举类型有3种取值,表示播放器的状态:
QMediaPlayer.StoppedState(停止状态);
QMediaPlayer.PlayingState(正在播放状态);
QMediaPlayer.PausedState(暂停播放状态)。
(2)durationChanged(duration)信号在文件的时间长度变化时发射,一般在切换播放文件时发射。参数duration是int类型,表示文件持续时间长度,单位ms。
(3)positionChanged(position)信号在当前文件播放位置变化时发射,可以反映文件播放进度。参数position是int类型,单位ms。

QMediaPlayer可以通过setMedia()函数设置播放单个文件,也可以通过setPlaylist()函数设置一个QMediaPlaylist类对象表示的播放列表,对列表文件进行播放,并且设置自动播放下一个文件或循环播放等。QMediaPlayer播放的文件可以是本地文件,也可以是网络上的文件。

QMediaPlaylist记录播放媒体文件信息,可以添加、移除文件,可以设置循环播放模式,在列表文件中自动切换文件,在当前播放文件切换时发射currentIndexChanged()信号和currentMediaChanged()信号。

2.窗口业务逻辑类初始化

示例就是用QMediaPlayer和QMediaPlaylist设计的一个音乐播放器,其运行时界面如图所示。

python 全屏重复播放视频_播放列表


窗口中间是一个QListWidget组件,上面的3个按钮用于文件管理,为播放列表添加、移除和清空文件,列表下方是播放控制按钮、音量控制、进度显示和控制。窗口是基于QMainWindow的,MainWindow.ui的界面可视化设计结果见示例源文件。

import sys

from PyQt5.QtWidgets import  QApplication, QMainWindow,QFileDialog,QListWidgetItem

from PyQt5.QtCore import  pyqtSlot,QUrl,QModelIndex,QDir,QFileInfo

from PyQt5.QtGui import QIcon

from PyQt5.QtMultimedia import QMediaPlayer, QMediaPlaylist,QMediaContent


from ui_MainWindow import Ui_MainWindow

class QmyMainWindow(QMainWindow): 
   def __init__(self, parent=None):
      super().__init__(parent)   #调用父类构造函数,创建窗体
      self.ui=Ui_MainWindow()    #创建UI对象
      self.ui.setupUi(self)      #构造UI界面

##      self.setWindowTitle("Demo10_1,音乐播放器")
      self.player = QMediaPlayer(self)
      self.playlist = QMediaPlaylist(self)
      self.player.setPlaylist(self.playlist)
      self.playlist.setPlaybackMode(QMediaPlaylist.Loop)    #循环模式

      self.__duration=""      #文件总时间长度
      self.__curPos=""        #当前播放到位置

	  self.player.stateChanged.connect(self.do_stateChanged)
      
      self.player.positionChanged.connect(self.do_positionChanged)
      
      self.player.durationChanged.connect(self.do_durationChanged)
      
      self.playlist.currentIndexChanged.connect(self.do_currentChanged)

在构造函数里创建了播放器self.player,创建了播放列表self.playlist,并为播放器设置了播放列表。

QMediaPlaylist类的setPlaybackMode(mode)函数可以设置播放列表的循环方式,参数mode是枚举类型.
QMediaPlaylist.PlaybackMode,有以下几种取值:
QMediaPlaylist.CurrentItemOnce(当前曲目只播放一次);
QMediaPlaylist.CurrentItemInLoop(当前曲目循环播放);
QMediaPlaylist.Sequential(从当前曲目开始顺序播放至列表结尾,然后结束播放);
QMediaPlaylist.Loop(列表循环播放);
QMediaPlaylist.Random(随机播放)。

构造函数里还创建了两个私有变量self.__duration和self.__curPos,分别表示文件总时间长度和当前播放的位置,用于在文件切换和播放进度变化时显示进度信息。

程序为播放器的 3 个信号设置了关联的槽函数,这 3 个信号的意义在前面已经说明。QMediaPlaylist的信号currentIndexChanged(position)在播放列表的当前曲目发生变化时发射,也为此信号设置了关联的槽函数。这4个自定义槽函数的代码:

##  =============自定义槽函数===============================        
   def do_stateChanged(self,state):    ##播放器状态变化
      self.ui.btnPlay.setEnabled(state!=QMediaPlayer.PlayingState)
      self.ui.btnPause.setEnabled(state==QMediaPlayer.PlayingState)
      self.ui.btnStop.setEnabled(state==QMediaPlayer.PlayingState)

   def do_positionChanged(self,position): ##当前文件播放位置变化,更新进度显示
      if (self.ui.sliderPosition.isSliderDown()): #在拖动滑块调整进度
         return
      self.ui.sliderPosition.setSliderPosition(position)
      secs=position/1000   #秒
      mins=secs/60         #分钟
      secs=secs % 60       #余数秒
      self.__curPos="%d:%d"%(mins,secs)
      self.ui.LabRatio.setText(self.__curPos+"/"+self.__duration)

   def do_durationChanged(self,duration):    ##文件时长变化
      self.ui.sliderPosition.setMaximum(duration)

      secs=duration/1000   #秒
      mins=secs/60         #分钟
      secs=secs % 60       #余数秒
      self.__duration="%d:%d"%(mins,secs)
      self.ui.LabRatio.setText(self.__curPos+"/"+self.__duration)

   def do_currentChanged(self,position):  ##playlist当前曲目变化
      self.ui.listWidget.setCurrentRow(position)
      item=self.ui.listWidget.currentItem()  #QListWidgetItem
      if (item != None):
         self.ui.LabCurMedia.setText(item.text())

3.播放列表的控制
窗口中间以一个QListWidget组件显示播放的文件列表,界面上显示的文件列表与self.playlist存储的文件列表保持同步。

窗口上方有“添加”“移除”“清空”3个按钮用于播放列表管理,下方有“上一曲目”和“下一曲目”按钮用于曲目移动,在窗体中间的QListWidget组件上双击某个项可以播放该曲目。这些按钮和组件的相关槽函数的代码:

##  ==========由connectSlotsByName() 自动连接的槽函数==================        
#  播放列表管理
   @pyqtSlot()    ##添加文件
   def on_btnAdd_clicked(self):  
   ##      curPath=os.getcwd()     #获取系统当前目录
   ##      curPath=QDir.homePath()
      curPath=QDir.currentPath()
      dlgTitle="选择音频文件" 
      filt="音频文件(*.mp3 *.wav *.wma);;所有文件(*.*)" 
      fileList,flt=QFileDialog.getOpenFileNames(self,dlgTitle,curPath,filt)
      count=len(fileList)
      if count<1:
         return

      filename=fileList[0]
      fileInfo=QFileInfo(filename)  #文件信息
      QDir.setCurrent(fileInfo.absolutePath())  #重设当前路径

      for i in range(count):
         filename=fileList[i] 
         fileInfo.setFile(filename)
         song=QMediaContent(QUrl.fromLocalFile(filename))
         self.playlist.addMedia(song)  #添加播放媒体
   ##         basename=os.path.basename(filename)    #文件名和后缀
         basename=fileInfo.baseName()
         self.ui.listWidget.addItem(basename)    #添加到界面文件列表

      if (self.player.state()!=QMediaPlayer.PlayingState):
         self.playlist.setCurrentIndex(0)
         self.player.play()
      
   @pyqtSlot()    ##移除一个文件
   def on_btnRemove_clicked(self): 
      pos=self.ui.listWidget.currentRow()
      item=self.ui.listWidget.takeItem(pos)     #python会自动删除

      if (self.playlist.currentIndex()==pos):   #是当前播放的曲目
         nextPos=0
         if pos>=1:
            nextPos=pos-1

         self.playlist.removeMedia(pos)   #从播放列表里移除
         if self.ui.listWidget.count()>0: #剩余个数
            self.playlist.setCurrentIndex(nextPos)
            self.do_currentChanged(nextPos)  #当前曲目变化
         else:
            self.player.stop()
            self.ui.LabCurMedia.setText("无曲目")
      else:
         self.playlist.removeMedia(pos)
      

   @pyqtSlot()    ##清空播放列表
   def on_btnClear_clicked(self):  
      self.playlist.clear()   #清空播放列表
      self.ui.listWidget.clear()  
      self.player.stop()      #停止播放
      
   ##   @pyqtSlot()    ##双击时切换播放文件
   def on_listWidget_doubleClicked(self,index):  
      rowNo=index.row()  #行号
      self.playlist.setCurrentIndex(rowNo)
      self.player.play()

#  播放控制
   @pyqtSlot()    ##播放
   def on_btnPlay_clicked(self):  
      if (self.playlist.currentIndex()<0):
         self.playlist.setCurrentIndex(0)
      self.player.play()

   @pyqtSlot()    ##暂停
   def on_btnPause_clicked(self):  
      self.player.pause()

   @pyqtSlot()    ##停止
   def on_btnStop_clicked(self):  
      self.player.stop()

   @pyqtSlot()    ##上一曲目
   def on_btnPrevious_clicked(self):  
      self.playlist.previous()

   @pyqtSlot()    ##下一曲目
   def on_btnNext_clicked(self):  
      self.playlist.next()

   @pyqtSlot()    ##静音控制
   def on_btnSound_clicked(self):  
      mute=self.player.isMuted()
      self.player.setMuted(not mute)
      if mute:
         self.ui.btnSound.setIcon(QIcon(":/icons/images/volumn.bmp"))
      else:
         self.ui.btnSound.setIcon(QIcon(":/icons/images/mute.bmp"))
      
   @pyqtSlot(int)    ##调节音量
   def on_sliderVolumn_valueChanged(self,value):  
      self.player.setVolume(value)

   @pyqtSlot(int)    ##文件进度调控
   def on_sliderPosition_valueChanged(self,value):  
      self.player.setPosition(value)

这里主要用到QMediaPlaylist类的以下几个函数。
(1)addMedia(content)函数:用于添加一个播放媒体content。
参数content是QMediaContent类型,这是用于表示媒体资源的类。一个媒体资源可以是本地音频或视频文件,也可以是网络上的资源。程序里创建播放媒体并添加到播放列表的语句是:

song=QMediaContent(QUrl.fromLocalFile(filename))
         self.playlist.addMedia(song)  #添加播放媒体

(2)QUrl.fromLocalFile(filename)的功能是使用QUrl的类函数fromLocalFile(),根据文件名filename创建一个指向此文件的QUrl对象。此QUrl对象传递给QMediaContent的构造函数,创建一个播放媒体song。所以song是指向本地文件的一个QMediaContent对象,再通过QMediaPlaylist.addMedia()函数添加到播放列表。
(3)removeMedia(pos)函数:从播放列表中移除序号为pos的一个项。
(4)clear()函数,用于清空播放列表。
(5)setCurrentIndex(pos)函数:设置序号pos的项为当前播放的媒体。
(6)previous()函数和 next()函数:在播放列表中前移和后移,移动时播放列表会发射信号currentIndexChanged(),从而自动更新界面组件listWidget里的当前条目。
4.播放控制
播放、暂停或停止播放器,只需调用QMediaPlayer相应的函数即可,界面上3个按钮的槽函数代码:
播放器的播放状态变化时会发射stateChanged()信号,在关联的自定义槽函数do_stateChanged()里更新3个按钮的使能状态。
音量控制由一个“静音”按钮和音量滑动条控制。
文件播放进度条在do_durationChanged()和do_positionChanged()两个自定义槽函数里会更新,显示当前文件播放进度。拖动滑动条的滑块可以设置文件播放位置。
程序运行测试时发现,如果正在播放音乐时退出程序,并不会自动停止播放(用Qt C++编写的相同程序是自动停止的),所以再为窗口的closeEvent()事件函数填写代码,停止音乐播放.

##  ===============event 处理函数==========
   def closeEvent(self,event):  ##窗体关闭时
##  窗口关闭时不能自动停止播放,需手动停止
      if (self.player.state()==QMediaPlayer.PlayingState):
         self.player.stop()