Search code examples
pythonpyside2qgraphicseffect

How to create a basic custom QGraphicsEffect in Qt?


I have been trying to create a basic QGraphicsEffect to change the colors of the widget, but first I tried to make an effect that does nothing like so:

class QGraphicsSepiaEffect(QtWidgets.QGraphicsEffect):
  def draw(painter):
    pixmap = sourcePixmap()
    painter.drawPixmap(pixmap.rect(), pixmap)

I am using PySide2. Though I checked all over the internet but couldn't find any sample, neither a template nor a real custom effect.

How can I write a basic effect to alter the colors of my widget?


Solution

  • As your question is basically how to create a custom effect then based on an example offered by the Qt community I have translated it to PySide2:

    import random
    import sys
    
    from PySide2 import QtCore, QtGui, QtWidgets
    # or
    # from PyQt5 import QtCore, QtGui, QtWidgets
    
    
    class HighlightEffect(QtWidgets.QGraphicsEffect):
        def __init__(self, offset=1.5, parent=None):
            super(HighlightEffect, self).__init__(parent)
            self._color = QtGui.QColor(255, 255, 0, 128)
            self._offset = offset * QtCore.QPointF(1, 1)
    
        @property
        def offset(self):
            return self._offset
    
        @property
        def color(self):
            return self._color
    
        @color.setter
        def color(self, color):
            self._color = color
    
        def boundingRectFor(self, sourceRect):
            return sourceRect.adjusted(
                -self.offset.x(), -self.offset.y(), self.offset.x(), self.offset.y()
            )
    
        def draw(self, painter):
            offset = QtCore.QPoint()
            try:
                pixmap = self.sourcePixmap(QtCore.Qt.LogicalCoordinates, offset)
            except TypeError:
                pixmap, offset = self.sourcePixmap(QtCore.Qt.LogicalCoordinates)
    
            bound = self.boundingRectFor(QtCore.QRectF(pixmap.rect()))
            painter.save()
            painter.setPen(QtCore.Qt.NoPen)
            painter.setBrush(self.color)
            p = QtCore.QPointF(offset.x() - self.offset.x(), offset.y() - self.offset.y())
            bound.moveTopLeft(p)
            painter.drawRoundedRect(bound, 5, 5, QtCore.Qt.RelativeSize)
            painter.drawPixmap(offset, pixmap)
            painter.restore()
    
    
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        w = QtWidgets.QWidget()
        lay = QtWidgets.QVBoxLayout(w)
        for _ in range(3):
            o = QtWidgets.QLabel()
            o.setStyleSheet(
                """background-color : {}""".format(
                    QtGui.QColor(*random.sample(range(255), 3)).name()
                )
            )
            effect = HighlightEffect(parent=o)
            o.setGraphicsEffect(effect)
            lay.addWidget(o)
        w.show()
        w.resize(640, 480)
        sys.exit(app.exec_())
    

    enter image description here