Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Autoresize QLabel pixmap keeping ratio without using classes?

We are making a GUI using PyQt and Qt Designer. Now we need that an image(pixmap) placed in a QLabel rescales nicely keeping ratio when the window is resized.

I've been reading other questions/answers but all of them use extended classes. As we are making constant changes in our UI, and it's created with Qt Creator, the .ui and (corresponding).py files are automatically generated so, if I'm not wrong, using a class-solution is not a good option for us because we should manually change the name of the class each time we update the ui.

Is there any option to autoresize the pixmap in a QLAbel keeping the ratio and avoiding using extended clases?

Thanks.

like image 436
user3061177 Avatar asked Jan 10 '14 10:01

user3061177


3 Answers

There are a couple of ways to do this.

Firstly, you can promote your QLabel in Qt Designer to a custom subclass that is written in python. Right-click the QLabel and select "Promote to...", then give the class a name (e.g. "ScaledLabel") and set the header file to the python module that the custom subclass class will be imported from (e.g. 'mylib.classes').

The custom subclass would then re-implement the resizeEvent like this:

class ScaledLabel(QtGui.QLabel):
    def __init__(self, *args, **kwargs):
        QtGui.QLabel.__init__(self)
        self._pixmap = QtGui.QPixmap(self.pixmap())

    def resizeEvent(self, event):
        self.setPixmap(self._pixmap.scaled(
            self.width(), self.height(),
            QtCore.Qt.KeepAspectRatio))

For this to work properly, the QLabel should have its size policy set to expanding or minimumExpanding, and the minimum size should be set to a small, non-zero value (so the image can be scaled down).

The second method avoids using a subclass and uses an event-filter to handle the resize events:

class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        ...
        self._pixmap = QtGui.QPixmap(self.label.pixmap())
        self.label.installEventFilter(self)

    def eventFilter(self, widget, event):
        if (event.type() == QtCore.QEvent.Resize and
            widget is self.label):
            self.label.setPixmap(self._pixmap.scaled(
                self.label.width(), self.label.height(),
                QtCore.Qt.KeepAspectRatio))
            return True
        return QtGui.QMainWindow.eventFilter(self, widget, event)
like image 50
ekhumoro Avatar answered Oct 24 '22 19:10

ekhumoro


Set background-image:, background-repeat: and background-position QSS properties for your label. You may do it via Forms editor or in code QWidget::setStyleSheet.

A good starting point for QSS (with examples) - http://doc.qt.io/qt-5/stylesheet-reference.html

like image 2
Dmitry Sazonov Avatar answered Oct 24 '22 19:10

Dmitry Sazonov


One way is to create a QWidget/QLabel subclass and reimplement the resizeEvent.

void QWidget::resizeEvent(QResizeEvent * event) [virtual protected]

This event handler can be reimplemented in a subclass to receive widget resize events which are passed in the event parameter. When resizeEvent() is called, the widget already has its new geometry. The old size is accessible through QResizeEvent::oldSize().

The widget will be erased and receive a paint event immediately after processing the resize event. No drawing need be (or should be) done inside this handler.

This would need to be done in C++ though, not PyQt.

Having that done, you could add your custom widget to the QtDesigner as follows:

Using Custom Widgets with Qt Designer

like image 1
lpapp Avatar answered Oct 24 '22 20:10

lpapp