pythonpyside2qpixmapqmdiarea

How to scale a QPixmap preserving aspect and centering the image?


I want to use an image (svg file) as background in an QMdiArea. I load the image as QPixmap and scale it in the resizeEvent method to the size of the QMdiArea using

self._background_scaled = self._background.scaled(self.size(), QtCore.Qt.KeepAspectRatio)
self.setBackground(self._background_scaled)

But that puts the image in the upper left corner and repeats it in either X or Y. I want the image to be centered.

How do I scale the QPixmap so it is resized preserving aspect ratio but then add borders to get the exact size?


Solution

  • The setBackground() method accepts a QBrush that is built based on the QPixmap you pass to it, but if a QBrush is built based on a QPixmap it will create the texture (repeating elements) and there is no way to change that behavior. So the solution is to override the paintEvent method and directly paint the QPixmap:

    import sys
    
    from PySide2 import QtCore, QtGui, QtWidgets
    
    
    def create_pixmap(size):
        pixmap = QtGui.QPixmap(size)
        pixmap.fill(QtCore.Qt.red)
        painter = QtGui.QPainter(pixmap)
        painter.setBrush(QtCore.Qt.blue)
        painter.drawEllipse(pixmap.rect())
        return pixmap
    
    
    class MdiArea(QtWidgets.QMdiArea):
        def __init__(self, parent=None):
            super().__init__(parent)
            pixmap = QtGui.QPixmap(100, 100)
            pixmap.fill(QtGui.QColor("transparent"))
            self._background = pixmap
    
        @property
        def background(self):
            return self._background
    
        @background.setter
        def background(self, background):
            self._background = background
            self.update()
    
        def paintEvent(self, event):
            super().paintEvent(event)
            painter = QtGui.QPainter(self.viewport())
            background_scaled = self.background.scaled(
                self.size(), QtCore.Qt.KeepAspectRatio
            )
            background_scaled_rect = background_scaled.rect()
            background_scaled_rect.moveCenter(self.rect().center())
            painter.drawPixmap(background_scaled_rect.topLeft(), background_scaled)
    
    
    if __name__ == "__main__":
    
        app = QtWidgets.QApplication(sys.argv)
    
        mdiarea = MdiArea()
        mdiarea.show()
    
        mdiarea.background = create_pixmap(QtCore.QSize(100, 100))
    
        sys.exit(app.exec_())