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

PyQt中QGraphicsView与QGraphicsVideoItem等尺寸适配问题

解决方案

问题根源

当前代码的核心问题是视频初始化阶段还未获取到有效尺寸,就在initUI里直接调用self.video_widget.setSize(self.mediaPlayer.videoSink().videoSize()),此时videoSize()可能返回空或默认尺寸,导致初始显示异常。另外,resizeFunc里的尺寸计算逻辑绕了弯路,没必要用mapFromScene转换,直接用视频原始尺寸和视图的缩放关系处理更准确。

修正后的代码

import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
from PySide6.QtMultimediaWidgets import QGraphicsVideoItem
from PySide6.QtMultimedia import QMediaPlayer, QAudioOutput


class MyWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.scene = QGraphicsScene()
        self.view = QGraphicsView(self.scene)
        # 关闭滚动条,避免视频适配时出现滚动
        self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        # 开启渲染优化
        self.view.setRenderHint(QPainter.Antialiasing)

        self.video_widget = QGraphicsVideoItem()
        self.scene.addItem(self.video_widget)

        self.mediaPlayer = QMediaPlayer()
        self.audioOutput = QAudioOutput()
        self.mediaPlayer.setAudioOutput(self.audioOutput)
        self.mediaPlayer.setVideoOutput(self.video_widget)

        # 监听视频尺寸变化信号,等视频加载完成后再获取有效尺寸
        self.mediaPlayer.videoSink().videoSizeChanged.connect(self.onVideoSizeChanged)

        self.mediaPlayer.setSource(QUrl.fromLocalFile("potrait.mp4"))

        # 添加可交互文本元素
        self.text = QGraphicsTextItem("test")
        self.text.setFlags(QGraphicsTextItem.ItemIsSelectable | 
                           QGraphicsTextItem.ItemIsMovable |
                           QGraphicsTextItem.ItemIsFocusable)
        font = QFont()
        font.setPointSize(100)
        self.text.setFont(font)
        self.scene.addItem(self.text)

        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)  # 去掉布局边距,让视图填满窗口
        layout.addWidget(self.view)

        self.mediaPlayer.play()

    def onVideoSizeChanged(self, size):
        if size.isValid():
            # 设置视频项尺寸为原始视频尺寸
            self.video_widget.setSize(size)
            # 更新场景范围为视频尺寸,确保视图适配基准正确
            self.scene.setSceneRect(QRectF(QPointF(0, 0), size))
            # 立即触发视图适配
            self.adjustViewToVideo()

    def adjustViewToVideo(self):
        # 让视频按宽高比填满可用区域,优先扩展填充
        self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatioByExpanding)
        # 获取适配后的视图内容尺寸,设置窗口最小尺寸
        fit_rect = self.view.mapFromScene(self.scene.sceneRect()).boundingRect()
        self.setMinimumSize(fit_rect.width(), fit_rect.height())
        # 首次显示时直接将窗口设为适配后的尺寸
        if not self.isVisible():
            self.resize(fit_rect.width(), fit_rect.height())

    def resizeEvent(self, event):
        self.adjustViewToVideo()


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

关键修改点

  • 监听视频尺寸信号:通过videoSizeChanged在视频加载完成后获取有效尺寸,解决初始尺寸无效的问题。
  • 优化适配逻辑:用Qt.KeepAspectRatioByExpanding实现视频填满可用区域且保持宽高比,贴近Premiere的预览效果。
  • 简化尺寸计算:移除冗余的showEvent和复杂的坐标转换,直接基于场景矩形计算适配尺寸。
  • 优化布局设置:去掉布局边距、关闭滚动条,让视图完全填充窗口,提升视觉连贯性。

效果说明

  1. 视频启动后自动以原始宽高比填满窗口,无需手动调整。
  2. 窗口大小变化时,视频自动适配并保持宽高比,始终填满可用区域。
  3. 场景尺寸由视频尺寸决定,文本元素基于视频坐标系进行交互。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 21:22:26