0

I'm trying to hide/show an image in PyQT using a mask. I'm able to obtain a nice result with the following code:

    self.picture = QLabel()
    self.pix = QPixmap('PyQt_Logo.png')
    self.picture.setPixmap(self.pix)
    self.picture.setMask(self.pix.createMaskFromColor(Qt.transparent, Qt.MaskOutColor))

But if I align the picture in the center of its layout container using:

    self.picture.setAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignVCenter)

the mask is not moved and it is applied left-aligned. How to apply the image mask on the centered image?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
saiwa
  • 31
  • 2

1 Answers1

0

The mask is always based in widget coordinates, but if you change the alignment of the image it won't translate the mask along with it.

A possible solution is to install an event filter on the label and update the mask whenever it's resized. In order to do so, we need to keep a persistent reference of the mask, but using a QRegion (which allows translation):

        self.baseMask = QRegion(self.pix.createMaskFromColor(Qt.transparent, Qt.MaskOutColor))
        self.picture.setMask(self.baseMask)
        self.picture.installEventFilter(self)
        # ...

    def eventFilter(self, obj, event):
        if event.type() == QEvent.Type.Resize:
            rect = self.picture.pixmap().rect()
            rect.moveCenter(self.picture.rect().center())
            self.picture.setMask(self.baseMask.translated(rect.topLeft()))
        return super().eventFilter(obj, event)

Alternatively, with a subclass:

class MaskLabel(QLabel):
    baseMask = None
    def setMask(self, mask):
        if isinstance(mask, QBitmap):
            mask = QRegion(mask)
        self.baseMask = mask
        self.updateMask()

    def updateMask(self):
        if self.baseMask and self.pixmap():
            rect = self.pixmap().rect()
            rect.moveCenter(self.rect().center())
            super().setMask(self.baseMask.translated(rect.topLeft()))

    def resizeEvent(self, event):
        self.updateMask()

Obviously, the above is only valid for centered images, if you need a different alignment, you need to verify the alignment direction and eventually translate the mask accordingly, based on the label rect().

musicamante
  • 41,230
  • 6
  • 33
  • 58