Reputation: 105
My objective is to create a gif or video from paintEvents and also show on QWidget (window).
I tried to paint the frame onto a QImage and then render it onto the QWidget, but I encounter some errors. Im not sure why I get such errors, the painter is only painting on the image, and from the docs it says I can render paint device after an end() (when I do put it after an end it complains for different reasons).
Before end()
QPainter::begin: A paint device can only be painted by one painter at a time.
QWidget::render: Cannot render with an inactive painter
After end(), should I not be inheriting QWidget?
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)
# I simplified the frame def
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') # Id like to later make it into a video. Preferably hold img in memory and append frame to video.
Upvotes: 1
Views: 203
Reputation: 105
I simplified my version of a solution of what I envisioned. I used imageio to be able to save as a video by append a frame on every iteration.
Youll require to pip install imageio and imageio[ffmpeg]
import imageio, numpy as np
from PySide6.QtWidgets import QWidget
from PySide6.QtCore import QPoint, QRect, QTimer, Qt
from PySide6.QtGui import QPainter, QPointList
WIDTH = 720
HEIGHT = 720
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.setFixedSize(WIDTH, HEIGHT)
self._totalFrames = 10
self._vid_writer = imageio.get_writer('video.avi', fps=10)
def closeEvent(self, event):
self._vid_writer.close()
self._timer.stop()
event.accept()
def frame(self):
self._points.clear()
self._points.append(QPoint(0,0))
if self._totalFrames > 0:
self.update()
pixmap = self.grab()
qimg = pixmap.toImage().convertToFormat(QImage.Format_RGB888)
array = np.ndarray((qimg.height(), qimg.width(), 3), buffer=qimg.constBits(), strides=[qimg.bytesPerLine(), 3, 1], dtype=np.uint8)
if not self._vid_writer.closed:
self._vid_writer.append_data(array)
else:
self._timer.stop()
self._vid_writer.close()
self._totalFrames -= 1
def paintEvent(self, event):
with QPainter(self) as painter:
rect = QRect(QPoint(0, 0), self.size())
painter.fillRect(rect, Qt.white)
painter.drawPoints(self._points)
Upvotes: 0