Force repaint on window move
-
Hi,
I am trying to achieve a transparent blurred background (like the acrylic on W10). I succeed to have the desired result visually.
To do so, I just grabbed a screenshot and blurred it. Then I display it in the paint event.
But I struggle to refresh the widget when my window move. I tried to call an update but it looks like when I move the window with the title bar, there is some lag. Which is less (but still) present if I ask and update when we move the window in another way (click+drag in the widget itself make it move).So my question is: Why is it so slow to perform the update (it take less than 10ms on my computer) and also why it is different when I move the window with the title bar.
Do you have some hints to make it work faster or maybe I do something really stupid and wrong and there is a magic way to do it :D
You can find the code below. Unfortunately, you will need to pip install some packages (numpy and scipy) to run the script
from PySide2.QtWidgets import * from PySide2.QtCore import * from PySide2.QtGui import * import numpy from scipy.ndimage.filters import gaussian_filter1d # need to pip install scipy import typing import sys import time def blurImage(image: QImage, radius: int, toPixmap: bool = False) -> typing.Union[QImage, QPixmap]: def arrayToQImage(im: numpy.ndarray, copy: bool = False) -> QImage: gray_color_table = [qRgb(i, i, i) for i in range(256)] if im is None: return QImage() if im.dtype == numpy.uint8: if len(im.shape) == 2: qim = QImage(im.data, im.shape[1], im.shape[0], im.strides[0], QImage.Format_Indexed8) qim.setColorTable(gray_color_table) return qim.copy() if copy else qim elif len(im.shape) == 3: if im.shape[2] == 3: qim = QImage(im.data, im.shape[1], im.shape[0], im.strides[0], QImage.Format_RGB888); return qim.copy() if copy else qim elif im.shape[2] == 4: qim = QImage(im.data, im.shape[1], im.shape[0], im.strides[0], QImage.Format_ARGB32); return qim.copy() if copy else qim if image.format() != QImage.Format_RGB32: image = image.convertToFormat(QImage.Format_RGB32) bits = image.bits() # contain the memory pointer to the pixel color list # As python is too slow, we use a numpy array to fill the color in a 3d dimenssional array array = numpy.frombuffer(bits, numpy.uint8).reshape((image.height(), image.width(), 4)) blurred = gaussian_filter1d(array, sigma=radius, axis=0) blurred = gaussian_filter1d(blurred, sigma=radius, axis=1) blurred_image = arrayToQImage(blurred.copy(), True) if toPixmap is True: return QPixmap.fromImage(blurred_image) else: return blurred_image class Window(QWidget): def __init__(self) -> None: super().__init__() self.screenshot: QPixmap = None self.clickedPos: QPoint = QPoint(0, 0) self.setLayout(QVBoxLayout()) for i in range(4): self.layout().addWidget(QLabel("plop")) def paintEvent(self, event: QPaintEvent) -> None: start = time.time() pos: QPoint = self.pos() painter: QPainter = QPainter(self) painter.drawPixmap( QRect( -1920 - pos.x(), 0 - pos.y()-30, self.screenshot.width(), self.screenshot.height(), ), self.screenshot ) painter.setOpacity(0.5) painter.setPen(Qt.NoPen) painter.setBrush(Qt.black) painter.drawRect(event.rect()) painter.end() return super().paintEvent(event) def show(self) -> None: screen = QApplication.screenAt(QCursor().pos()) s_geo = screen.geometry() screenshot = screen.grabWindow(0, 0, 0, s_geo.width(), s_geo.height()) self.screenshot = blurImage(screenshot.toImage(), 9, True) return super().show() def updateBG(self) -> None: self.repaint(QRect(0, 0, self.width(), self.height())) def mousePressEvent(self, event: QMouseEvent) -> None: self.clickedPos = event.pos() - QPoint(0, -30) return super().mousePressEvent(event) def mouseMoveEvent(self, event: QMouseEvent) -> None: self.move(self.mapToGlobal(event.pos()) - self.clickedPos) # self.updateBG() return super().mouseMoveEvent(event) def moveEvent(self, event: QMoveEvent) -> None: self.updateBG() return super().moveEvent(event) app = QApplication() w = Window() w.show() sys.exit(app.exec_())Thank you very much for your help. Feel free to ask me any more information if needed :)