You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt5 QMediaPlayer停止播放后窗口缩放出现画面残留问题求助

PyQt5 QMediaPlayer视频停止后窗口缩放出现画面残留的解决方法

在PyQt5中使用QMediaPlayer时,视频播放结束或调用stop()方法后,缩放窗口会导致视频部件位置出现画面残留现象。

最小复现代码

import sys
from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QPushButton, QFileDialog, QSlider
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
from PyQt5.QtMultimediaWidgets import QVideoWidget

class Player(QMainWindow):
    def __init__(self, parent=None):
        super(Player, self).__init__(parent)
        
        self.media_player = QMediaPlayer(self)
        self.video_widget = QVideoWidget(self)
        self.slider = QSlider(Qt.Horizontal)

        self.open_button = QPushButton("Open Media File")
        self.open_button.clicked.connect(self.open_file)

        layout = QVBoxLayout()
        layout.addWidget(self.video_widget)
        layout.addWidget(self.open_button)
        layout.addWidget(self.slider)

        widget = QWidget(self)
        widget.setLayout(layout)
        self.setCentralWidget(widget)

        self.media_player.setVideoOutput(self.video_widget)
        self.media_player.positionChanged.connect(self.update_slider)
        self.slider.sliderMoved.connect(self.set_position)

    def open_file(self):
        file_dialog = QFileDialog.getOpenFileName(self, "Open Media File")
        if file_dialog[0]:
            self.set_and_play_file(file_dialog[0])

    def set_and_play_file(self, selected_file):
        self.media_player.setMedia(QMediaContent(QUrl.fromLocalFile(selected_file)))
        self.media_player.play()

    def update_slider(self, position):
        self.slider.setMaximum(int(self.media_player.duration() / 1000))
        self.slider.setValue(int(position / 1000))

    def set_position(self, position):
        self.media_player.setPosition(int(position * 1000))

if __name__ == "__main__":
    app = QApplication(sys.argv)
    player = Player()
    player.show()
    sys.exit(app.exec_())

已尝试的无效方法

  • 监听QMediaPlayer.EndOfMedia状态,用pause()替代stop()并将播放位置设为0,仅部分改善,仍有残留
  • 设置以下部件属性无效果:
    self.video_widget.setAttribute(Qt.WA_OpaquePaintEvent, False)
    self.video_widget.setAutoFillBackground()
    self.video_widget.setAttribute(Qt.WA_NoSystemBackground, True)
    
  • 尝试重写video widget的paintEvent()绘制红线,因QPainter使用经验不足未成功

彻底解决方法

方法1:自定义QVideoWidget重写resizeEvent强制刷新

问题核心是视频停止后,QVideoWidget在窗口缩放时未正确刷新区域。自定义视频部件,在大小变化时主动触发刷新:

from PyQt5.QtWidgets import QVideoWidget
from PyQt5.QtCore import QResizeEvent

class CustomVideoWidget(QVideoWidget):
    def resizeEvent(self, event: QResizeEvent) -> None:
        super().resizeEvent(event)
        self.update()  # 强制刷新整个部件区域

替换原代码中的QVideoWidget为自定义类:

self.video_widget = CustomVideoWidget(self)

方法2:监听播放状态,重置视频输出并刷新

当视频停止时,先清除再重新设置视频输出,触发部件刷新:

# 在Player类的__init__方法中添加信号连接
self.media_player.stateChanged.connect(self.on_state_changed)
self.media_player.mediaStatusChanged.connect(self.on_media_status_changed)

def on_state_changed(self, state):
    if state == QMediaPlayer.StoppedState:
        # 清除并重新绑定视频输出
        self.media_player.setVideoOutput(None)
        self.media_player.setVideoOutput(self.video_widget)
        self.video_widget.update()  # 强制刷新

def on_media_status_changed(self, status):
    if status == QMediaPlayer.EndOfMedia:
        self.media_player.stop()  # 触发停止状态处理逻辑

环境说明:Windows 10 x64 1809、PyQt5 5.15.10

内容的提问来源于stack exchange,提问作者deeffest

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 00:02:40