1
votes

I am trying to create an image editor using PyQt5.

I sub-classed QLabel to create a label which displays an image through setPixmap. The class ensures that, whenever the label is resized, the image maintains aspect ratio.

I put 2 of those labels inside a horizontal layout and set their pixmaps to 2 images.

All works great, except when the window is resized in certain ways.

When I start increasing width of the window, everything works great. But when I start shrinking it, the first label start shrinking, while the second one stays the same. The first label keeps shrinking until it can't decrease in size anymore, forcing the second one to shrink.

This is not what I want. I want both labels to stay the same size while window gets resized. How can I accomplish that?

Here is minimal part of my code to reproduce my problem:

import sys

from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QPixmap

class ImageLabel(QtWidgets.QLabel):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.setMinimumSize(1,1)
        self.setScaledContents(False)

        self.pixmap = QPixmap(1, 1)

    def set_image(self, image_path):
        pixmap = QPixmap(image_path)
        self.set_pixmap(pixmap)

    def set_pixmap(self, pixmap):
        self.pixmap = pixmap
        self.setPixmap(pixmap)

    def resizeEvent(self, event):
        self.setPixmap(self.scaled_pixmap())

    def scaled_pixmap(self):
        return self.pixmap.scaled(
            self.size(),
            Qt.KeepAspectRatio,
            Qt.SmoothTransformation
        )

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi()
        self.start()

    def setupUi(self):
        self.setWindowTitle('Image Editor')

        self.centralWidget = QtWidgets.QWidget()

        self.hlayout = QtWidgets.QHBoxLayout()

        self.image_1 = ImageLabel()
        self.hlayout.addWidget(self.image_1)

        self.image_2 = ImageLabel()
        self.hlayout.addWidget(self.image_2)

        self.centralWidget.setLayout(self.hlayout)
        self.setCentralWidget(self.centralWidget)

        self.resize(800, 600)

    def start(self):
        self.image_1.set_image(
            r"orig.jpg"
        )

        self.image_2.set_image(
            r"edit.jpg"
        )

app = QtWidgets.QApplication(sys.argv)
mainWindow = MainWindow()

mainWindow.show()
exitCode = app.exec_()

sys.exit(exitCode)
1

1 Answers

2
votes

Instead of using QLabel, the simplest is to use a QGraphicsView with a QGraphicsPixmapItem:

import sys
from PyQt5 import QtCore, QtGui, QtWidgets

class ImageLabel(QtWidgets.QGraphicsView):
    def __init__(self, *args, **kwargs):
        super(ImageLabel, self).__init__(*args, **kwargs)
        self.setScene(QtWidgets.QGraphicsScene())
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) 
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)

    def setImage(self, filename):
        self.setPixmap(QtGui.QPixmap(filename))

    def setPixmap(self, pixmap):
        item = QtWidgets.QGraphicsPixmapItem(pixmap)
        item.setTransformationMode(QtCore.Qt.SmoothTransformation)
        self.scene().addItem(item)

    def resizeEvent(self, event):
        r = self.scene().itemsBoundingRect()
        self.fitInView(r, QtCore.Qt.KeepAspectRatio)
        super(ImageLabel, self).resizeEvent(event)


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi()
        self.start()

    def setupUi(self):
        self.setWindowTitle('Image Editor')

        self.image_1 = ImageLabel()
        self.image_2 = ImageLabel()

        self.centralWidget = QtWidgets.QWidget()
        self.setCentralWidget(self.centralWidget)

        hlayout = QtWidgets.QHBoxLayout(self.centralWidget)
        hlayout.addWidget(self.image_1)
        hlayout.addWidget(self.image_2)

        self.resize(800, 600)

    def start(self):
        self.image_1.setImage(
            r"orig.jpg"
        )

        self.image_2.setImage(
            r"edit.jpg"
        )

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    mainWindow = MainWindow()

    mainWindow.show()
    exitCode = app.exec_()

    sys.exit(exitCode)