0

In PyQt I'm trying to create a label which contains a pixmap and have the pixmap automatically resize as the label resizes — say, as a result of the window the label is in resizing.

I am experiencing several problems:

  • The window refuses to resize smaller than its original size.
  • If you resize the window to a larger size, you can never resize back to a smaller size.
  • As the window resizes, the label also resizes correctly, but its pixmap does not repaint properly. It appears to "tear" or repeat pixels horizontally and/or vertically.

I started by creating a class PixmapLabel that inherits from QLabel since I wanted to override the resizeEvent event:

import sys

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

# You can plug in a path to an image of your choosing.
IMAGE_PATH = '../assets/launch_image.jpeg'


class PixmapLabel(QLabel):
    """
    A label widget that has a pixmap. As the label resizes so does the 
    pixmap.
    """

    def __init__(self, pixmap: QPixmap = None):
        super().__init__()
        self.setStyleSheet('background-color: lightgray')
        self.setPixmap(pixmap)

    def resizeEvent(self, event: QResizeEvent):
        """As the PixmapLabel resizes, resize its pixmap."""
        super().resizeEvent(event)
        self.setPixmap(self.pixmap())

    def setPixmap(self, pixmap: QPixmap):
        if pixmap is None:
            return

        # Resize the widget's pixmap to match the width of the widget preserving 
        # the aspect ratio.
        width = self.width()
        pixmap = pixmap.scaledToWidth(width)
        super().setPixmap(pixmap)

Here is the code for the MainWindow (which derives from QDialog):

class MainWindow(QDialog):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('PyQt PixmapLabelWidget Test')
        self.resize(300, 300)

        # Set the window's main layout.
        self.main_layout = QVBoxLayout()
        self.setLayout(self.main_layout)

        # Add a single widget — a PixmapLabel — to the main layout.
        self.lbl_image = PixmapLabel()
        self.main_layout.addWidget(self.lbl_image)
        pixmap = QPixmap(IMAGE_PATH)
        self.lbl_image.setPixmap(pixmap)

Finally, here's the code to run the Python app/script:

if __name__ == '__main__':
    app = QApplication([])
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())

Here's how the window initially renders with the label and its pixmap: https://cln.sh/gEldrO+.

Here's what it looks like after it has been resized: https://cln.sh/MuhknK+.

You should be able to see the "tearing."

Any suggestions about how to make this widget resize its pixmap correctly?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Steve Wehba
  • 161
  • 1
  • 6
  • avoid override, only use `label.setScaledContents(True)` – eyllanesc Sep 26 '21 at 04:01
  • @eyllanesc Thanks. Just using a plain `QLabel` and calling `setScaledContents(True)` does automatically resize the embedded `QPixmap` and does not "tear" the image. However, it also does not maintain the aspect ratio. Is there a way to `setScaledContents(True)` AND maintain the aspect ratio of the embed pixmap? – Steve Wehba Sep 26 '21 at 20:56
  • Keeping this aspect ratio is not in your post so don't take it into account. If you want to keep it then you can use QGraphicsView as I show in this answer: https://stackoverflow.com/a/69187941/6622587 – eyllanesc Sep 26 '21 at 21:06

0 Answers0