PyQt6使用QAudioOutput与QMediaPlayer实现音频淡入淡出效果求助
解决PyQt音频淡入淡出UI阻塞问题
核心思路
之前的实现方式出现UI阻塞,本质是音量调整逻辑阻塞了主线程的事件循环。使用Qt内置的QPropertyAnimation可以无阻塞实现属性平滑过渡,完全不会影响UI响应。
修改后完整代码
import sys from PyQt6 import QtWidgets from PyQt6.QtCore import QUrl, QPropertyAnimation from PyQt6.QtMultimedia import QMediaPlayer, QAudioOutput from PyQt6.QtWidgets import QWidget, QVBoxLayout, QPushButton, QStyle class MainWindowUi(QtWidgets.QMainWindow): def __init__(self): super().__init__() self._setup_ui() self.setWindowTitle('sound fading') self.setGeometry(100, 100, 100, 100) def _setup_ui(self): self.central_widget = QWidget(self) self.central_widget_layout = QVBoxLayout(self.central_widget) self.setCentralWidget(self.central_widget) self.player = AudioPlayer() self.user_action = -1 # 0 - stopped, 1 - playing, 2 - paused self.play_button = QPushButton() self.play_button.clicked.connect(self.play_pause_button_clicked) self.play_icon = self.style().standardIcon(QStyle.StandardPixmap.SP_MediaPlay) self.pause_icon = self.style().standardIcon(QStyle.StandardPixmap.SP_MediaPause) self.play_button.setIcon(self.play_icon) self.central_widget_layout.addWidget(self.play_button) def play(self): print("Play") self.play_button.setIcon(self.pause_icon) self.user_action = 1 # 替换为实际音频文件路径 self.player.setSource(QUrl.fromLocalFile("你的音频文件路径.mp3")) self.player.play() def pause(self): print("Pause") self.play_button.setIcon(self.play_icon) self.user_action = 2 self.player.pause() def unpause(self): print("Unpause") self.play_button.setIcon(self.pause_icon) self.user_action = 1 self.player.play() def play_pause_button_clicked(self): if self.user_action <= 0: self.play() elif self.user_action == 1: self.pause() elif self.user_action == 2: self.unpause() class AudioPlayer(QMediaPlayer): def __init__(self, parent=None, fade_duration=600): super().__init__(parent) self.audio_output = QAudioOutput() self.setAudioOutput(self.audio_output) self.target_volume = 0.3 # 最终播放音量 self.audio_output.setVolume(self.target_volume) self.fade_duration = fade_duration # 淡入淡出时长,单位毫秒 # 初始化音量动画对象,绑定音频输出的volume属性 self.volume_anim = QPropertyAnimation(self.audio_output, b"volume") self.volume_anim.setDuration(self.fade_duration) def play(self): # 停止正在运行的动画,避免状态切换冲突 self.volume_anim.stop() # 淡入逻辑:先将音量置0,再平滑升到目标音量 self.audio_output.setVolume(0) super().play() self.volume_anim.setStartValue(0) self.volume_anim.setEndValue(self.target_volume) self.volume_anim.start() def pause(self): self.volume_anim.stop() # 淡出逻辑:从当前音量平滑降到0,动画结束后再执行暂停 self.volume_anim.setStartValue(self.audio_output.volume()) self.volume_anim.setEndValue(0) self.volume_anim.finished.connect(self._finish_pause) self.volume_anim.start() def _finish_pause(self): super().pause() # 重置音量为目标值,方便下次播放时淡入 self.audio_output.setVolume(self.target_volume) # 断开信号绑定,避免后续动画重复触发该方法 self.volume_anim.finished.disconnect(self._finish_pause) if __name__ == '__main__': app = QtWidgets.QApplication(sys.argv) mainWindow = MainWindowUi() mainWindow.show() sys.exit(app.exec())
实现说明
- 所有动画逻辑由Qt原生事件循环调度,全程不阻塞主线程,播放/暂停按钮可随时点击响应
- 默认淡入淡出时长为600毫秒,可通过修改
AudioPlayer初始化时的fade_duration参数自定义时长 - 每次启动新动画前会停止正在运行的动画,避免用户快速切换播放状态时出现音量异常
内容的提问来源于stack exchange,提问作者N1teShad0w
相关产品推荐
相关产品推荐

