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

使用QPainter/QImage生成GIF/视频并在QWidget显示的报错求助

问题描述

目标是通过paintEvent生成GIF/视频,同时在QWidget窗口中显示内容。尝试先将画面绘制到QImage再渲染到QWidget时出现一系列错误:

  • 在QPainter.end()前操作:
    QPainter::begin: A paint device can only be painted by one painter at a time.
    QWidget::render: Cannot render with an inactive painter
    
  • 移到end()后操作:
    QWidget::repaint: Recursive repaint detected
    QPainter::begin: A paint device can only be painted by one painter at a time.
    QPainter::fillRect: Painter not active
    QPainter::scale: Painter not active
    QPainter::drawPoints: Painter not active
    QPainter::end: Painter not active, aborted
    QPainter::begin: A paint device can only be painted by one painter at a time.
    QWidget::render: Cannot render with an inactive painter
    

当前代码:

class PlotWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._timer = QTimer(self)
        self._timer.setInterval(100)
        self._timer.timeout.connect(self.frame)

        self._points = QPointList()
        
        self._qimg = QImage(WIDTH, HEIGHT, QImage.Format_RGB32)

    # 简化后的frame方法
    def frame(self):
        self._points.clear()
        self._points.append(QPoint(0,0))
        self.update()

    def paintEvent(self, event):
        with QPainter(self._qimg) as painter:
            rect = QRect(QPoint(0, 0), self.size())
            painter.fillRect(rect, Qt.white)
            painter.drawPoints(self._points)
            self.render(self._qimg)
        self._qimg.save('test.png', 'PNG') # 后续希望将帧存入内存并拼接成视频,而非保存为PNG

需求:后续将帧存入内存并拼接成视频,而非保存为PNG。

解决方案

错误原因分析

  1. 绘图设备冲突:操作QImage的QPainter未结束时调用self.render(self._qimg),会尝试给QWidget创建新的QPainter,导致同一绘图设备被多个画家占用。
  2. 递归重绘:self.render会间接触发paintEvent,形成递归调用,引发"Recursive repaint detected"错误。
  3. 画家状态错误:end()后操作时,原QPainter已释放,后续操作会提示"Painter not active"。

修正后的代码

核心思路:先在QImage上完成绘制,再用独立的QPainter将QImage绘制到QWidget窗口,避免render带来的递归和冲突问题。同时将QImage帧存入内存队列,供后续视频生成使用。

from PySide6.QtWidgets import QWidget, QPainter
from PySide6.QtGui import QImage, QPoint, QRect, Qt
from PySide6.QtCore import QTimer, QPointList
import cv2
import numpy as np

WIDTH = 640
HEIGHT = 480

class PlotWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._timer = QTimer(self)
        self._timer.setInterval(100)
        self._timer.timeout.connect(self.frame)
        self._timer.start()  # 启动定时器

        self._points = QPointList()
        self._qimg = QImage(WIDTH, HEIGHT, QImage.Format_RGB32)
        self._frame_queue = []  # 内存中存储帧的队列

        # 视频初始化(示例用OpenCV)
        self._video_writer = cv2.VideoWriter(
            'output.mp4',
            cv2.VideoWriter_fourcc(*'mp4v'),
            10,  # 帧率,和定时器间隔对应(100ms=10帧/秒)
            (WIDTH, HEIGHT)
        )

    def frame(self):
        self._points.clear()
        self._points.append(QPoint(0, 0))
        # 可添加更多测试点
        self._points.append(QPoint(100, 100))
        self.update()

    def paintEvent(self, event):
        # 第一步:绘制到QImage
        with QPainter(self._qimg) as img_painter:
            rect = QRect(0, 0, WIDTH, HEIGHT)
            img_painter.fillRect(rect, Qt.white)
            img_painter.drawPoints(self._points)
        
        # 第二步:将QImage绘制到当前QWidget窗口
        with QPainter(self) as widget_painter:
            widget_painter.drawImage(0, 0, self._qimg)
        
        # 第三步:将帧存入内存队列,同时写入视频(可选)
        # QImage转成OpenCV可用的格式
        img_cv = cv2.cvtColor(np.array(self._qimg), cv2.COLOR_RGB2BGR)
        self._frame_queue.append(img_cv)
        if self._video_writer.isOpened():
            self._video_writer.write(img_cv)

    def closeEvent(self, event):
        # 关闭时释放视频写入器
        if self._video_writer.isOpened():
            self._video_writer.release()
        super().closeEvent(event)

关键说明

  • 避免render调用:用QPainter.drawImage直接将QImage绘制到窗口,不会触发递归重绘,也不会产生绘图设备冲突。
  • 内存帧存储:用_frame_queue列表保存每帧的OpenCV格式图像,后续可直接用于视频拼接。
  • 视频生成:示例用OpenCV的VideoWriter实时写入视频,也可在所有帧生成完成后再统一拼接。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 18:16:29