Search code examples
qtqwidgetqlabelqpixmap

How to display image in ratio as PreserveAspectFit in Qt Widgets


In qml, I can simply do this

    Image {
        anchors.fill: parent
        source: "/path/to/coo/image"
        fillMode: Image.PreserveAspectFit
    }

I don't want to use QML due to its ties with JavaScript. How can I do this with Widgets ?

I tried using QLabel but it has no option to set aspect ratio or fillMode. I think I can manually scale the pixmap and then set it to QLabel but that wont be reactive (resize image when window is resized) like QML. Isn't there any image specefic widget in Qt to do this ?


Solution

  • A possible solution is to use QGraphicsView, QGraphicsScene and QGraphicsPixmapItem:

    #include <QApplication>
    #include <QGraphicsPixmapItem>
    #include <QGraphicsView>
    #include <QPixmap>
    
    class Viewer: public QGraphicsView{
    public:
        Viewer(QWidget *parent = nullptr): QGraphicsView(parent){
            setScene(new QGraphicsScene(this));
            m_pixmapItem = scene()->addPixmap(QPixmap());
            setAlignment(Qt::AlignCenter);
        }
        QPixmap pixmap() const{
             return m_pixmapItem->pixmap();
        }
        void setPixmap(const QPixmap &newPixmap){
            m_pixmapItem->setPixmap(newPixmap);
            fitInView(m_pixmapItem, Qt::KeepAspectRatio);
        }
    protected:
        void resizeEvent(QResizeEvent *event){
            QGraphicsView::resizeEvent(event);
            fitInView(m_pixmapItem, Qt::KeepAspectRatio);
        }
    private:
        QGraphicsPixmapItem *m_pixmapItem;
    };
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        QPixmap pixmap(100, 200);
        pixmap.fill(Qt::green);
    
        Viewer w;
        w.resize(640, 480);
        w.setPixmap(pixmap);
        w.show();
    
        return a.exec();
    }
    

    Python version:

    from PyQt5.QtCore import Qt
    from PyQt5.QtGui import QPixmap
    from PyQt5.QtWidgets import QApplication, QGraphicsScene, QGraphicsView
    
    
    class Viewer(QGraphicsView):
        def __init__(self, parent=None):
            super().__init__(parent)
            self.setScene(QGraphicsScene(self))
            self.m_pixmapItem = self.scene().addPixmap(QPixmap())
            self.setAlignment(Qt.AlignCenter)
    
        @property
        def pixmap(self):
            return self.m_pixmapItem.pixmap()
    
        @pixmap.setter
        def pixmap(self, newPixmap):
            self.m_pixmapItem.setPixmap(newPixmap)
            self.fitInView(self.m_pixmapItem, Qt.KeepAspectRatio)
    
        def resizeEvent(self, event):
            super().resizeEvent(event)
            self.fitInView(self.m_pixmapItem, Qt.KeepAspectRatio)
    
    
    def main():
        import sys
    
        app = QApplication(sys.argv)
    
        pixmap = QPixmap(100, 200)
        pixmap.fill(Qt.green)
    
        w = Viewer()
        w.resize(640, 480)
        w.pixmap = pixmap
        w.show()
    
        sys.exit(app.exec_())
    
    
    if __name__ == "__main__":
        main()
    ``