39. 媒体播放器

一、音频播放

  QSoundEffect 可以用来播放无压缩的音频文件(典型的是 .wav 文件),通过它我们不仅能够以低延迟的方式来播放音频,还能够对音频进行更进一步的操作(比如控制音量)。该类非常适合用来播放交互音效,如弹出框的提示音、游戏音效等。

  我们可以在终端中使用 pip 安装 PySide6 模块。默认是从国外的主站上下载,因此,我们可能会遇到网络不好的情况导致下载失败。我们可以在 pip 指令后通过 -i 指定国内镜像源下载

pip install pyside6 -i https://mirrors.aliyun.com/pypi/simple

  国内常用的 pip 下载源列表:

  创建 QSoundEffect 类的对象方法如下:

QSoundEffect(parent:QObject=None)
QSoundEffect(audioDevice:QAudioDevice, parent:QObject=None)

  QSoundEffect 类常用方法如下:

# 实例方法
setSource(url:QUrl) -> None                                                     # 设置音频源
source() -> QUrl                                                                # 获取音频源

setAudioDevice(device:QAudioDevice) -> None                                     # 设置音频设备
audioDevice() -> QAudioDevice                                                   # 获取音频设备

setLoopCount(loopCount:int) -> None                                             # 设置播放次数
loopCount() -> int                                                              # 获取播放次数

loopsRemaining() -> int                                                         # 获取剩余播放次数

setMuted(muted:bool) -> None                                                    # 设置是否静音
isMuted() -> bool                                                               # 获取是否静音

setVolume(volume:float) -> None                                                 # 设置音量
volume() -> float                                                               # 获取音量

isPlaying() -> bool                                                             # 获取是否正在播放

isLoaded() -> bool                                                              # 获取是否已经加载声源

status() -> QSoundEffet.Status                                                  # 获取播放状态

# 槽函数                              
play() -> None                                                                  # 开始播放
stop() -> None                                                                  # 停止播放

# 静态方法                            
supportedMimeTypes() -> List[str]                                               # 获取支持的类型

  QSoundEffect 类常用信号如下:

audioDeviceChanged()                                                            # 音频设备发生改变时发射信号
loadedChanged()                                                                 # 加载状态发生改变时发射信号
loopCountChanged()                                                              # 循环次数发生改变时发射信号
loopsRemainingChanged()                                                         # 剩余循环次数发生改变时发射信号
mutedChanged()                                                                  # 静音状态发生改变时发射信号
playingChanged()                                                                # 播放状态发生改变时发射信号
sourceChanged()                                                                 # 音频源发生改变时发射信号  
statusChanged()                                                                 # 状态发生改变时发射信号
volumeChanged()                                                                 # 音量发生改变时发射信号

  用 setSource(url:QUrl) 方法 设置音频源,参数 QUrl 可以是 指向网络的文件,也可以是 本机文件。用 source() 方法 获取音频源 QUrl

  用 status() 方法 获取当前的播放状态,返回值是枚举类型 QSoundEffect.Status,可取值如下:

QSoundEffect.Status.Null
QSoundEffect.Status.Loading
QSoundEffect.Status.Ready
QSoundEffect.Status.Error

  新建一个 ui.py 文件,用来存放 UI 相关的代码。

from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import QLabel, QPushButton, QCheckBox, QSlider
from PySide6.QtWidgets import QVBoxLayout, QHBoxLayout, QFormLayout
from PySide6.QtCore import Qt

class MyUi:
    def setupUi(self, window:QWidget):
        window.resize(300, 100)                                                 # 1.设置窗口对象大小

        vertical_layout = QVBoxLayout(window)                                   # 2.创建一个垂直布局

        self.choose_file_label = QLabel("未选择文件")                             # 3.创建一个标签,用来显示选择的文件,并添加到垂直布局中
        vertical_layout.addWidget(self.choose_file_label)

        form_layout = QFormLayout()                                             # 4.创建一个表单布局,并添加到垂直布局中
        vertical_layout.addLayout(form_layout)

        self.volume_slider = QSlider()                                          # 5.创建一个滑块,并添加到表单布局中
        form_layout.addRow("音量:", self.volume_slider)

        self.volume_slider.setOrientation(Qt.Orientation.Horizontal)            # 6.设置滑块的显示方向
      
        self.volume_slider.setRange(0, 100)                                     # 7.设置滑块的范围
      
        self.volume_slider.setValue(80)                                         # 8.设置滑块的值

        horizontal_layout = QHBoxLayout()                                       # 9.创建一个水平布局,并添加到垂直布局中
        vertical_layout.addLayout(horizontal_layout)

        self.choose_file_button = QPushButton("选择音频文件")                     # 10.创建一个按钮,并添加到水平布局中
        horizontal_layout.addWidget(self.choose_file_button)

        self.player_button = QPushButton("开始播放")
        horizontal_layout.addWidget(self.player_button)
      
        self.player_button.setEnabled(False)                                    # 11.设置按钮为禁用状态
      
        self.silence_checkBox = QCheckBox("是否静音")
        horizontal_layout.addWidget(self.silence_checkBox)

  新建一个 widget.py 文件,用来存放业务逻辑相关的代码。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QFileDialog
from PySide6.QtCore import QUrl, Qt
from PySide6.QtMultimedia import QSoundEffect

from ui import MyUi

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法

        self.__ui = MyUi()
        self.__ui.setupUi(self)                                                 # 2.初始化页面

        self.audio = QSoundEffect()                                             # 3、创建音频播放对象

        self.__ui.choose_file_button.clicked.connect(self.choose_file)          # 4.按钮被点击后激活信号,选择文件
        self.__ui.player_button.clicked.connect(self.player_audio)              # 5.按钮被点击后激活信号,播放或暂停音频
        self.__ui.volume_slider.valueChanged.connect(self.change_volume)        # 6.滑块值改变时激活信号,改变音量
        self.__ui.silence_checkBox.checkStateChanged.connect(self.change_silence_state) # 7.复选框状态改变时激活信号,改变静音状态

        self.audio.playingChanged.connect(self.audio_playing_changed)           # 8.音频播放状态改变时激活信号

    def choose_file(self):
        # 1.创建文件对话框
        file_name, filter = QFileDialog.getOpenFileName(self, caption="选择音频文件", dir="./assets/audio", filter="音频文件(*.wav)")
        if file_name == "":
            return
      
        message = file_name.split("/")[-1]
        self.__ui.choose_file_label.setText(f"你选择了【{message}】音频文件")      # 2.选择文件后更改标签的文本
      
        self.audio.setSource(QUrl.fromLocalFile(file_name))                     # 3.设置音频播放对象的声源
        self.audio.setLoopCount(1)                                              # 4.设置音频播放对象的播放次数 

        self.change_volume(self.__ui.volume_slider.value())                     # 5.设置音量
      
        self.__ui.player_button.setEnabled(True)                                # 6.启用播放按钮
        self.__ui.player_button.setText("开始播放")                              # 7.重置为开始播放按钮

        self.change_silence_state(self.__ui.silence_checkBox.checkState())      # 8.设置是否静音

    def player_audio(self):
        if self.__ui.player_button.text() == "开始播放":
            self.audio.play()                                                   # 1.开始播放
            self.__ui.player_button.setText("停止播放")                          # 2.重新设置按键文本为停止播放
        elif self.__ui.player_button.text() == "停止播放":
            self.audio.stop()                                                   # 3.停止播放  
            self.__ui.player_button.setText("开始播放")                          # 4.重新设置按键文本为开始播放

    def change_volume(self, value:int):
        self.audio.setVolume(value / 100)                                       # 1.设置音量

    def change_silence_state(self, state:Qt.CheckState):
        if state == Qt.CheckState.Checked:                                      # 1.判断是否勾选静音复选框
            self.audio.setMuted(True)                                           # 2.如果勾选,则设置静音
        elif state == Qt.CheckState.Unchecked:
            self.audio.setMuted(False)                                          # 3.如果没有勾选,取消静音

    def audio_playing_changed(self):
        if self.audio.isPlaying():                                              # 1.判断音频是否正在播放
            self.__ui.player_button.setText("停止播放")                          # 2.如果音频正在播放,重新设置播放音频按键文本为停止播放
        else:
            self.__ui.player_button.setText("开始播放")                          # 3.如果音频播放完成,重新设置播放音频按键文本为开始播放

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

二、媒体播放器

  播放器 QMediaPlayer 可以播放音频和视频,它可以直接播放的格式有限。要播放更多格式的音频或视频,例如 mp4 格式的视频文件,需要在本机上安装解码器。

  QMediaPlayer 继承自 QObject,用 QMediaPlayer 定义播放器实例对象的方法如下所示:

QMediaPlayer(parent:QObject=None)

  其中 parent 是继承自 QObject 类的实例对象。

  QMediaPlayer 类的常用方法:

# 实例方法
sourceDevice() -> QIODevice                                                     # 获取音频或视频源QIODevice

setActiveAudioTrack(index:int) -> None                                          # 设置当前的声道
activeAudioTrack() -> int                                                       # 获取当前的声道

setActiveVideoTrack(index:int) -> None                                          # 设置当前的视频轨道
activeVideoTrack() -> int                                                       # 获取当前的视频轨道

setActiveSubtitleTrack(index:int) -> None                                       # 设置当前的子标题轨道
activeSubtitleTrack() -> int                                                    # 获取当前的子标题轨道

playbackRate() -> float                                                         # 获取播放速率
isSeekable() -> bool                                                            # 获取是否可以定位到某一播放时间
position() -> int                                                               # 获取当前的播放时间(毫秒)

setAudioOutput(output:QAudioOutput) -> None                                     # 设置播放音频的设备
setVideoOutput(widget:QVideoWidget) -> None                                     # 设置显示视频的控件
setVideoOutput(item:QGraphcicVideoItem) -> None                                 # 设置显示视频的图项

setLoops(loops:int) -> None                                                     # 设置循环播放次数
loops() -> int                                                                  # 获取循环播放次数

duration() -> int                                                               # 获取音频或视频可以播放的总时长(毫秒)

playbackState() -> QMedioPlayer.PlaybackState                                   # 获取播放状态
mediaStatus() -> QMedioPlayer.MediaStatus                                       # 获取播放器所处的状态

error() -> QMediaPlayer.Error                                                   # 获取出错原因
errorString() -> str                                                            # 获取出错信息

hasAudio() -> bool                                                              # 获取多媒体中是否有音频
hasVideo() -> bool                                                              # 获取多媒体中是否有视频

bufferProgress() -> float                                                       # 获取缓冲百分比,100%时才可以播放

# 槽方法
setSource(source:QUrl, str) -> None                                             # 设置要播放的音频或视频源
setSourceDevice(device:QIODevice, sourceUrl:QUrl=QUrl()) -> None                # 设置音频或视频地址QUrl
setPlaybackRate(rate:float) -> None                                             # 设置播放速率
setPosition(position:int) -> None                                               # 设置播放时间(毫秒)

play() -> None                                                                  # 播放音频或视频
pause() -> None                                                                 # 暂停播放
stop() -> None                                                                  # 停止播放并将播放位置重置到开头

  QMediaPlayer 类的常用信号:

tracksChanged()                                                                 # 轨道发生改变时发射信号
activeTracksChanged()                                                           # 当轨道发生改变时发射信号

audioOutputChanged()                                                            # 音频输出设备发生改变时发射信号

bufferProgressChanged(progress:float)                                           # 缓冲进度发生改变时发射信号

durationChanged(duration:int)                                                   # 播放时长发生改变时发射信号

errorChanged()                                                                  # 出错信息发生改变时发射信号
errorOccurred(error:QMediaPlayer.Error, errorString:str)                        # 播放出错时发射信号

hasAudioChanged(available:bool)                                                 # 可播放音频的状态发生改变时发射信号
hasVideoChanged(videoAvailable:bool)                                            # 可播放视频的状态发生改变时发射信号

loopsChanged()                                                                  # 播放次数发生改变时发射信号

mediaStatusChanged(status:QMediaPlayer.MediaStatus)                             # 播放器所在的状态发生改变时发射信号

metaDataChanged()                                                               # 播放器元数据发生改变时发射信号

playbackRateChanged(rate:float)                                                 # 播放速度发生改变时发射信号
playbackStateChanged(state:QMediaPlayer.PlaybackState)                          # 播放状态发生改变时发射信号 
playingChanged(playing:bool)                                                    # 播放状态发生改变时发射信号
positionChanged(position:int)                                                   # 播放位置发生改变时发射信号

seekableChanged(seekable:bool)                                                  # 可定位播放状态发生改变时发射信号

sourceChanged(media:QUrl)                                                       # 音频或视频源发生改变时发射信号

videoOutputChanged()                                                            # 关联的视频播放器发生改变时发射信号

  要播放音频或视频,首先需要给 QMediaPlayer 设置媒体源。可以用 setSource(source:QUrl) 方法或用 setSourceDevice(device:QIODevice,sourceUrl:QUrl=Default(QUrl)) 方法 设置媒体文件,其中 sourceUrl 是可选参数,用于 获取额外的信息。用 source()sourceDevice() 分别 获取媒体源 QUrlQIODevice

  要显示视频,需要将 QMediaPlayer 与显示视频的控件关联,可以显示视频的控件有 QVideoWidgetQGraphicsVideoItem,关联方法分别是 setVideoOutput(widget:QVideoWidget)setVideoOutput(item:QGraphicsVideoItem) 。要播放音频,需要用 setAudioOutput(output:QAudioOutput)方法 设置音频输出设备

  用 setPlaybackRate(rate:float) 方法 设置播放速率,参数 rate 值为 1.0 表示 正常播放;参数 rate 可以为 负值,表示 回放速率。有些多媒体不支持回放。

  用 setLoops(loops:int) 方法 设置循环播放次数,参数 loops 可取值 QMediaPlayer.Loops.Once(一次)、QMediaPlayer.Loops.Infinite(无限次)或 其它整数。

  用 state() 方法 获取播放状态,返回值为 QMediaPlayer.State 枚举值,可能取值如下:

QMediaPlayer.State.StoppedState
QMediaPlayer.State.PlayingState
QMediaPlayer.State.PausedState

  用 playbackState() 方法 获取播放器的播放状态,返回的值是 QMediaPlayer.PlaybackState 枚举值,可能取值如下:

QMediaPlayer.PlaybackState.StoppedState
QMediaPlayer.PlaybackState.PlayingState
QMediaPlayer.PlaybackState.PausedState

  用 mediaStatus() 方法 获取播放器所处的状态,返回值是 QMediaPlayer.MediaStatus 枚举值,可能取值如下:

QMediaPlayer.MediaStatus.NoMedia
QMediaPlayer.MediaStatus.LoadingMedia
QMediaPlayer.MediaStatus.LoadedMedia
QMediaPlayer.MediaStatus.StalledMedia
QMediaPlayer.MediaStatus.BufferingMedia
QMediaPlayer.MediaStatus.BufferedMedia
QMediaPlayer.MediaStatus.EndOfMedia
QMediaPlayer.MediaStatus.InvalidMedia

  用 error() 方法 获取播放器出错信息,返回值是 QMediaPlayer.Error 枚举值,可能取值如下:

QMediaPlayer.Error.NoError
QMediaPlayer.Error.ResourceError
QMediaPlayer.Error.FormatError
QMediaPlayer.Error.NetworkError
QMediaPlayer.Error.AccessDeniedError

三、音频输出

  播放器 QMediaPlayer 需要 关联音频输出设备 才能播放音频。音频输出 需要定义 QAudioOutput 的实例,QAudioOutput 用于连接 QMediaPlayer 与音频输出设备。QAudioOutput 继承自 QObject

  用 QAudioOutput 创建实例对象的方法如下所示:

QAudioOutput(parent:QObject=None)
QAudioOutput(device:QAudioDevice, parent:QObject=None)

  其中 QAudioDevice本机上的音频输入输出设备

  QAudioOutput 类的常用方法如下:

# 实例方法
volume() -> float                                                               # 获取音量
isMuted() -> bool                                                               # 获取是否静音
device() -> QAudioDevice                                                        # 获取音频设备

# 槽方法
setVolume(volume:float) -> None                                                 # 设置音量,参数取值范围为0~1
setMuted(muted:bool) -> None                                                    # 设置静音状态
setDevice(device:QAudioDevice) -> None                                          # 设置音频设备

  QAudioOutput 类的常用信号如下:

deviceChanged()                                                                 # 音频设备发生改变时发射信号
mutedChanged(muted:bool)                                                        # 静音状态发生改变时发送信号
volumeChanged(volume:float)                                                     # 音量发生改变时候发射信号

  修改 ui.py 文件的内容。

from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import QLabel, QPushButton, QCheckBox, QSlider
from PySide6.QtWidgets import QVBoxLayout, QHBoxLayout, QFormLayout
from PySide6.QtCore import Qt

class MyUi:
    def setupUi(self, window:QWidget):
        window.resize(300, 100)                                                 # 1.设置窗口对象大小

        vertical_layout = QVBoxLayout(window)                                   # 2.创建一个垂直布局

        self.choose_file_label = QLabel("未选择文件")                             # 3.创建一个标签,用来显示选择的文件,并添加到垂直布局中
        vertical_layout.addWidget(self.choose_file_label)

        form_layout = QFormLayout()                                             # 4.创建一个表单布局,并添加到垂直布局中
        vertical_layout.addLayout(form_layout)

        self.volume_slider = QSlider()                                          # 5.创建一个滑块,并添加到表单布局中
        form_layout.addRow("音量:", self.volume_slider)

        self.volume_slider.setOrientation(Qt.Orientation.Horizontal)            # 6.设置滑块的显示方向
      
        self.volume_slider.setRange(0, 100)                                     # 7.设置滑块的范围
      
        self.volume_slider.setValue(80)                                         # 8.设置滑块的值

        horizontal_layout = QHBoxLayout()                                       # 9.创建一个水平布局,并添加到垂直布局中
        vertical_layout.addLayout(horizontal_layout)

        self.choose_file_button = QPushButton("选择音频文件")                     # 10.创建一个按钮,并添加到水平布局中
        horizontal_layout.addWidget(self.choose_file_button)

        self.player_button = QPushButton("开始播放")
        horizontal_layout.addWidget(self.player_button)

        self.player_button.setEnabled(False)                                    # 11.设置按钮为禁用状态

        self.stop_button = QPushButton("停止播放")
        horizontal_layout.addWidget(self.stop_button)

        self.stop_button.setEnabled(False)
      
        self.silence_checkBox = QCheckBox("是否静音")
        horizontal_layout.addWidget(self.silence_checkBox)

  修改 widget.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QFileDialog
from PySide6.QtCore import QUrl, Qt
from PySide6.QtMultimedia import QMediaPlayer, QAudioOutput

from ui import MyUi

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法

        self.__ui = MyUi()
        self.__ui.setupUi(self)                                                 # 2.初始化页面

        self.mediaPlayer = QMediaPlayer()                                       # 3、创建媒体播放器对象
        self.audioOutput = QAudioOutput()                                       # 4、创建音频播放对象
        self.mediaPlayer.setAudioOutput(self.audioOutput)                       # 5、设置播放音频的设备

        self.__ui.choose_file_button.clicked.connect(self.choose_file)          # 6.按钮被点击后激活信号,选择文件
        self.__ui.player_button.clicked.connect(self.player_audio)              # 7.按钮被点击后激活信号,播放或暂停音频
        self.__ui.stop_button.clicked.connect(self.stop_player_audio)           # 8.按钮被点击后激活信号,停止播放音频
        self.__ui.volume_slider.valueChanged.connect(self.change_volume)        # 9.滑块值改变时激活信号,改变音量
        self.__ui.silence_checkBox.checkStateChanged.connect(self.change_silence_state) # 10.复选框状态改变时激活信号,改变静音状态

        self.mediaPlayer.playbackStateChanged.connect(self.reset_play)          # 11、播放状态发生改变时激活信号

    def choose_file(self):
        # 1.创建文件对话框
        file_name, filter = QFileDialog.getOpenFileName(self, caption="选择音频文件", dir="./assets/audio", filter="音频文件(*.mp3 *.wav *.flac)")
        if file_name == "":
            return
      
        message = file_name.split("/")[-1]
        self.__ui.choose_file_label.setText(f"你选择了【{message}】音频文件")      # 2.选择文件后更改标签的文本
      
        self.mediaPlayer.setSource(QUrl.fromLocalFile(file_name))               # 3.设置音频播放对象的声源
        self.mediaPlayer.setLoops(1)                                            # 4、设置媒体播放器对象的播放次数

        self.change_volume(self.__ui.volume_slider.value())                     # 5.设置音量
      
        self.__ui.player_button.setEnabled(True)                                # 6.启用播放按钮和停止按钮
      
        self.__ui.player_button.setText("开始播放")                              # 7.重置为开始播放按钮

        self.change_silence_state(self.__ui.silence_checkBox.checkState())      # 8.设置是否静音

    def player_audio(self):
        if self.__ui.player_button.text() == "开始播放":
            self.mediaPlayer.play()                                             # 1.开始播放
            self.__ui.player_button.setText("暂停播放")                          # 2.重新设置播放音频按键文本为停止播放
            self.__ui.stop_button.setEnabled(True)                              # 3.启用停止播放按键
        elif self.__ui.player_button.text() == "暂停播放":
            self.mediaPlayer.pause()                                            # 4.暂停播放  
            self.__ui.player_button.setText("开始播放")                          # 5.重新设置播放音频按键文本为开始播放

    def stop_player_audio(self):
        if self.mediaPlayer.playbackState() != QMediaPlayer.PlaybackState.StoppedState: # 1.判断当前是否停止播放
            self.mediaPlayer.stop()                                             # 2.停止播放
            self.__ui.player_button.setText("开始播放")                          # 3.重新设置播放音频按键文本为开始播放
            self.__ui.stop_button.setEnabled(False)                             # 4.停止播放后禁用停止播放按键

    def change_volume(self, value:int):
        self.audioOutput.setVolume(value / 100)                                 # 1.设置音量

    def change_silence_state(self, state:Qt.CheckState):
        if state == Qt.CheckState.Checked:                                      # 1.判断是否勾选静音复选框
            self.audioOutput.setMuted(True)                                     # 2.如果勾选,则设置静音
        elif state == Qt.CheckState.Unchecked:
            self.audioOutput.setMuted(False)                                    # 3.如果没有勾选,取消静音

    def reset_play(self, state:QMediaPlayer.PlaybackState):
        if state == QMediaPlayer.PlaybackState.StoppedState:                    # 1.如果停止播放
            self.__ui.player_button.setText("开始播放")                          # 2.将播放音频按钮设置为开始播放
            self.__ui.stop_button.setEnabled(False)                             # 3.停止播放按钮设置为禁用

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

四、视频输出

  播放器 QMediaPlayer 需要 关联视频输出控件 才能播放视频。视频输出 需要用到 视频控件 QVideoWidget视频图项 QGraphicsVideoItem,其中 QGraphicsVideoItem 作为图项应用于场景中。QVideoWidget 继承自 QWidgetQGraphicsVideoItem 继承自 QGraphicsObject

  用 QVideoWidgetQGraphicsVideoItem 创建实例对象的方法如下所示:

QVideoWidget(parent:QWidget=None)

QGraphicsVideoItem(parent:QGrapicsItem=None)

  QVideoWidget 类的常用方法如下:

# 实例方法
aspectRatioMode() -> Qt.AspectRatioMode                                         # 获取长宽比模式

isFullScreen() -> bool                                                          # 获取是否全屏显示

# 槽方法              
setAspectRatioMode(mode:Qt.AspectRatioMode) -> None                             # 设置长宽比模式
setFullScreen(fullScreen:bool) -> None                                          # 设置全屏显示

  QVideoWidget 类的常用信号如下:

aspectRatioModeChanged(mode:Qt.AspectRatioMode)                                 # 长宽比模式发生改变时发射信号
fullScreenChanged(fullScreen:bool)                                              # 全屏状态发生改变时发射信号

  QGraphicsVideoItem 类的常用方法如下:

setAspectRatioMode(mode:Qt.AspectRatioMode) -> None                             # 设置长宽比模式
aspectRatioMode() -> Qt.AspectRatioMode                                         # 获取长宽比模式
setOffset(offset:Union[QSize, QSizeF]) -> None                                  # 设置偏移量
offset() -> QPointF                                                             # 获取偏移量
setSize(size:Union[QSize, QSizeF]) -> None                                      # 设置尺寸
size() -> QSizeF                                                                # 获取尺寸

  QGraphicsVideoItem 类的常用方法如下:

nativeSizeChanged(size:QSizeF)                                                  # 尺寸发生改变时发射信号

  其中,用 setAspectRatioMode(mode:Qt.AspectRatioMode) 方法 设置视频控件所播放视频的长宽比模式,参数 modeQt.AspectRatioMode 类型的枚举值,可以取值如下:

Qt.AspectRatioMode.IgnoreAspectRatio                                            # 不保持比例关系
Qt.AspectRatioMode.KeepAspectRatio                                              # 保持原比例关系
Qt.AspectRatioMode.KeepAspectRatioByExpanding                                   # 通过扩充保持原比例关系

长宽比模式

  修改 ui.py 文件的内容。

from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import QLabel, QPushButton, QCheckBox, QSlider, QComboBox
from PySide6.QtWidgets import QVBoxLayout, QHBoxLayout, QFormLayout
from PySide6.QtCore import Qt
from PySide6.QtMultimediaWidgets import QVideoWidget

class MyUi:
    def setupUi(self, window:QWidget):
        window.resize(800, 600)                                                 # 1.设置窗口对象大小

        vertical_layout = QVBoxLayout(window)                                   # 2.创建一个垂直布局

        self.choose_file_label = QLabel("未选择文件")                             # 3.创建一个标签,用来显示选择的文件,并添加到垂直布局中
        vertical_layout.addWidget(self.choose_file_label)

        self.choose_file_label.setFixedHeight(20)                               # 4.设置标签的高度

        self.videoWidget = QVideoWidget()                                       # 5、创建视频播放对象,并添加到布局中
        vertical_layout.addWidget(self.videoWidget, 1)

        form_layout = QFormLayout()                                             # 6.创建一个表单布局,并添加到垂直布局中
        vertical_layout.addLayout(form_layout)

        self.volume_slider = QSlider()                                          # 7.创建一个滑块,并添加到表单布局中
        form_layout.addRow("音量:", self.volume_slider)

        self.volume_slider.setFixedHeight(20)                                   # 8.设置滑块高度

        self.volume_slider.setOrientation(Qt.Orientation.Horizontal)            # 9.设置滑块的显示方向
      
        self.volume_slider.setRange(0, 100)                                     # 10.设置滑块的范围
      
        self.volume_slider.setValue(80)                                         # 11.设置滑块的值

        horizontal_layout = QHBoxLayout()                                       # 12.创建一个水平布局,并添加到垂直布局中
        vertical_layout.addLayout(horizontal_layout)

        self.choose_file_button = QPushButton("选择文件")                        # 13.创建一个按钮,并添加到水平布局中
        horizontal_layout.addWidget(self.choose_file_button)

        self.player_button = QPushButton("开始播放")
        horizontal_layout.addWidget(self.player_button)

        self.player_button.setEnabled(False)                                    # 14.设置按钮为禁用状态

        self.stop_button = QPushButton("停止播放")
        horizontal_layout.addWidget(self.stop_button)

        self.stop_button.setEnabled(False)

        rate_label = QLabel("播放速度:")
        horizontal_layout.addWidget(rate_label)

        rate_label.setFixedWidth(60)
      
        self.rate_comboBox = QComboBox()
        horizontal_layout.addWidget(self.rate_comboBox)

        self.rate_comboBox.setFixedWidth(60)
        self.rate_comboBox.addItems(["0.5", "0.75", "1.0", "1.25", "1.5", "2.0"])
        self.rate_comboBox.setCurrentIndex(2)
      
        self.silence_checkBox = QCheckBox("是否静音")
        horizontal_layout.addWidget(self.silence_checkBox)

  修改 widget.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QFileDialog
from PySide6.QtCore import QUrl, Qt
from PySide6.QtMultimedia import QMediaPlayer, QAudioOutput

from ui import MyUi

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法

        self.__ui = MyUi()
        self.__ui.setupUi(self)                                                 # 2.初始化页面

        self.mediaPlayer = QMediaPlayer()                                       # 3、创建媒体播放器对象
        self.audioOutput = QAudioOutput()                                       # 4、创建音频播放对象
        self.mediaPlayer.setAudioOutput(self.audioOutput)                       # 5、设置播放音频的设备
        self.mediaPlayer.setVideoOutput(self.__ui.videoWidget)                  # 6、设置播放视频的设备

        self.__ui.choose_file_button.clicked.connect(self.choose_file)          # 7.按钮被点击后激活信号,选择文件
        self.__ui.player_button.clicked.connect(self.player_audio)              # 8.按钮被点击后激活信号,播放或暂停音频
        self.__ui.stop_button.clicked.connect(self.stop_player_audio)           # 9.按钮被点击后激活信号,停止播放音频
        self.__ui.volume_slider.valueChanged.connect(self.change_volume)        # 10.滑块值改变时激活信号,改变音量
        self.__ui.silence_checkBox.checkStateChanged.connect(self.change_silence_state) # 11.复选框状态改变时激活信号,改变静音状态
        self.__ui.rate_comboBox.currentTextChanged.connect(self.change_player_rate)     # 12.下拉框内容改变时激活信号,改变播放速度

        self.mediaPlayer.playbackStateChanged.connect(self.reset_play)          # 13、播放状态发生改变时激活信号

    def choose_file(self):
        # 1.创建文件对话框
        file_name, filter = QFileDialog.getOpenFileName(self, 
                                caption="选择音频文件", 
                                dir="./assets/videos", 
                                filter="视频文件(*.mp4 *.avi);;音频文件(*.mp3 *.wav *.flac)"
                            )
        if file_name == "":
            return
      
        message = file_name.split("/")[-1]
        self.__ui.choose_file_label.setText(f"你选择了【{message}】文件")          # 2.选择文件后更改标签的文本
      
        self.mediaPlayer.setSource(QUrl.fromLocalFile(file_name))               # 3.设置音频播放对象的声源
        self.mediaPlayer.setLoops(1)                                            # 4、设置媒体播放器对象的播放次数

        self.change_volume(self.__ui.volume_slider.value())                     # 5.设置音量
        self.change_player_rate(self.__ui.rate_comboBox.currentText())          # 6.设置播放速度
      
        self.__ui.player_button.setEnabled(True)                                # 6.启用播放按钮和停止按钮
      
        self.__ui.player_button.setText("开始播放")                              # 7.重置为开始播放按钮

        self.change_silence_state(self.__ui.silence_checkBox.checkState())      # 8.设置是否静音

    def player_audio(self):
        if self.__ui.player_button.text() == "开始播放":
            self.mediaPlayer.play()                                             # 1.开始播放
            self.__ui.player_button.setText("暂停播放")                          # 2.重新设置播放音频按键文本为停止播放
            self.__ui.stop_button.setEnabled(True)                              # 3.启用停止播放按键
        elif self.__ui.player_button.text() == "暂停播放":
            self.mediaPlayer.pause()                                            # 4.暂停播放  
            self.__ui.player_button.setText("开始播放")                          # 5.重新设置播放音频按键文本为开始播放

    def stop_player_audio(self):
        if self.mediaPlayer.playbackState() != QMediaPlayer.PlaybackState.StoppedState: # 1.判断当前是否停止播放
            self.mediaPlayer.stop()                                             # 2.停止播放
            self.__ui.player_button.setText("开始播放")                          # 3.重新设置播放音频按键文本为开始播放
            self.__ui.stop_button.setEnabled(False)                             # 4.停止播放后禁用停止播放按键

    def change_volume(self, value:int):
        self.audioOutput.setVolume(value / 100)                                 # 1.设置音量

    def change_silence_state(self, state:Qt.CheckState):
        if state == Qt.CheckState.Checked:                                      # 1.判断是否勾选静音复选框
            self.audioOutput.setMuted(True)                                     # 2.如果勾选,则设置静音
        elif state == Qt.CheckState.Unchecked:
            self.audioOutput.setMuted(False)                                    # 3.如果没有勾选,取消静音

    def change_player_rate(self, text:str):
        self.mediaPlayer.setPlaybackRate(float(text))                           # 1.设置播放速度

    def reset_play(self, state:QMediaPlayer.PlaybackState):
        if state == QMediaPlayer.PlaybackState.StoppedState:                    # 1.如果停止播放
            self.__ui.player_button.setText("开始播放")                          # 2.将播放音频按钮设置为开始播放
            self.__ui.stop_button.setEnabled(False)                             # 3.停止播放按钮设置为禁用

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

五、动画播放

  QMovie 用于 播放无声音的静态动画(例如 gif 文件),它在 PySide6.Gui 模块中,需要用 QLabelsetMovie(movie:QMovie) 方法与 QLabel 相关联来播放动画。

  用 QMovie 类创建播放动画的实例对象的方法如下:

QMoive(parent:QObject=None)
QMoive(filename:str, format:Union[QByteArray, bytes]=Default(QByteArray), parent:QObject=None)
QMoive(device:QIODevice, format:Union[QByteArray, bytes]=Default(QByteArray), parent:QObject=None)

  其中 parent 是继承自 QObject 的实例对象,可以用文件名或指向图形动画的 QIODevice 设备来指定动画源;format 用来 指定动画来源的格式,取值类型是 QByteArraybytes ,例如 b'gif'b'webp',如果不指定格式,系统会自行选择合适的格式。

  QMoive 类常用的方法如下:

# 实例方法
setFileName(fileName:str) -> None                                               # 设置动画文件
fileName() -> str                                                               # 获取动画文件

setDevice(device:QIODevice) -> None                                             # 设置设备
device() -> QIODevice                                                           # 获取设备

setFormat(format:Union[QByteArray, bytes]) -> None                              # 设置动画格式
format() -> QByteArray                                                          # 获取动画格式

setScaledSize(size:QSize) -> None                                               # 设置尺寸
scaledSize() -> QSize                                                           # 获取尺寸

speed() -> int                                                                  # 获取正常播放速度的百分比

setCacheMode(mode:QMovie.CacheMode) -> None                                     # 设置缓冲模式
cacheMode() -> QMovie.CacheMode                                                 # 获取缓冲模式

setBackgroundColor(color:Union[QColor, Qt.GlobalColor, str]) -> None            # 设置背景颜色
backgroundColor() -> QColor                                                     # 获取背景颜色

state() -> QMovie.MovieState                                                    # 获取播放状态

currentFrameNumber() -> int                                                     # 获取当前帧编号
currentImage() -> QImage                                                        # 获取当前帧图片
currentPixmap() -> QPixmap                                                      # 获取当前帧图片
frameCount() -> int                                                             # 获取总帧数
frameRect() -> QRect                                                            # 获取当前帧的矩形

jumpToFrame(frameNumber:int) -> bool                                            # 跳转到指定帧,成功返回True

isValid() -> bool                                                               # 获取动画源是否有效

lastErrorString() -> str                                                        # 获取最近的错误信息
lastError() -> QImageReader.ImageReaderError                                    # 获取最近的错误信息

loopCount() -> int                                                              # 获取循环次数

nextFrameDelay() -> int                                                         # 获取播放下一帧的等待时间

# 槽方法
setSpeed(percentSpeed:int) -> None                                              # 设置正常播放速度的百分比

start() -> None                                                                 # 开始播放动画
stop() -> None                                                                  # 停止播放动画
setPaused(paused:bool)                                                          # 暂停或继续播放动画

jumpToNextFrame() -> bool                                                       # 跳转到下一帧,成功返回True

# 静态方法
static supportedFormats() -> list[QByteArray]                                   # 获取支持的动画格式

  QMoive 类常用的信号如下:

error(error:QImageReader.ImageReaderError)                                      # 出错时发射信号
finished()                                                                      # 播放完成时发射信号
frameChanged(frameNumber:int)                                                   # 帧发生改变时发射信号
resized(size:QSize)                                                             # 调整尺寸时发射信号
started()                                                                       # 用start()方法开始播放时发射信号
stateChanged(state:QMovie.MovieState)                                           # 播放状态改变时发射信号
updated(rect:QRect)                                                             # 更新时发射信号

  用 setFileName(fileName:str)setDevice(device:QIODevice) 方法 设置动画源。用 isValid() 方法 获取动画源是否有效。用 setFormat(format:Union[QByteArray,bytes]) 方法 设置动画源的格式

  用 start() 方法 开始播放动画,用 stop() 方法 停止播放,用 pause(True) 方法 暂停播放,用 pause(False) 方法 继续播放。用 setSpeed(percentSpeed:int) 方法 设置播放速度,参数是 正常播放速度的百分比值,例如 setSpeed(200) 表示播放速度是原播放速度的 2 倍。

  用 setCacheMode(mode:QMovie.CacheMode) 方法 设置播放时是否进行缓存,参数 modeQMovie.CacheMode 类型的枚举值,可以取值如下:

QMovie.CacheMode.CacheNone
QMovie.CacheMode.CacheAll

  用 state() 方法可以 获得当前的播放状态,播放状态的返回值可能有以下取值:

QMovie.MovieState.NoRunning
QMovie.MovieState.Running
QMovie.MovieState.Paused

  用 lastErrorString() 方法 获取最近出错的信息。用 lastError() 方法 获取出错信息,返回值是 QImageReader.ImageReaderError 的枚举值,可能取值如下:

QImageReader.ImageReaderError.UnknownError
QImageReader.ImageReaderError.FileNotFoundError
QImageReader.ImageReaderError.DeviceError
QImageReader.ImageReaderError.UnsupportedFormatError
QImageReader.ImageReaderError.InvalidDataError

  修改 ui.py 文件的内容。

from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import QLabel, QToolBar
from PySide6.QtWidgets import QVBoxLayout
from PySide6.QtCore import Qt
from PySide6.QtGui import QAction, QIcon

class MyUi:
    def setupUi(self, window:QWidget):
        window.resize(800, 600)                                                 # 1.设置窗口对象大小

        layout = QVBoxLayout(window)                                            # 2.创建一个垂直布局

        self.toolBar = QToolBar()                                               # 3.创建一个工具栏,并添加到布局中
        layout.addWidget(self.toolBar)

        self.toolBar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextUnderIcon)         # 4.设置工具栏的显示样式

        self.open_file_action = QAction(icon=QIcon("assets/images/1.ico"), text="打开文件")  # 5.创建一个动作,并添加到工具栏中
        self.toolBar.addAction(self.open_file_action)

        self.label = QLabel()                                                   # 6.创建一个标签,并添加到布局中
        layout.addWidget(self.label)

        self.label.setAlignment(Qt.AlignmentFlag.AlignCenter)                   # 7.设置标签居中

  修改 widget.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QFileDialog
from PySide6.QtGui import QMovie

from ui import MyUi

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法

        self.__ui = MyUi()
        self.__ui.setupUi(self)                                                 # 2.初始化页面

        self.__ui.open_file_action.triggered.connect(self.open_file)            # 4.动作被触发时发射信号

    def open_file(self):
        # 1.创建文件对话框
        file_name, filter = QFileDialog.getOpenFileName(self, caption="选择文件", dir="./assets/images", filter="动图文件(*.gif);;")
        if file_name == "":
            return
      
        self.movie = QMovie()                                                   # 2.创建一个QMovie对象
        self.__ui.label.setMovie(self.movie)                                    # 3.设置标签的动画

        self.movie.setFileName(file_name)                                       # 4.设置文件名
        self.movie.start()                                                      # 5.开始播放
      

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
posted @ 2025-05-09 19:45  星光映梦  阅读(26)  评论(0)    收藏  举报