-1

I read a lot of posts/threads but I can't get it to work.

I'd like to fit every Image to a GraphicsView regardless if it is smaller or bigger then the view.

What's wrong?

void frmMain::on_btLoadImage_clicked()
{
    QGraphicsScene *scene;
    QPixmap image;

    QString imgPath = "O:/IMG_0001.JPG";
    QRectF sceneRect = ui->imgMain->sceneRect();

    image.load(imgPath);

    image.scaled (sceneRect.width (),sceneRect.height (), Qt::KeepAspectRatio, Qt::SmoothTransformation);

    scene = new QGraphicsScene(this);
    scene->addPixmap(image);
    scene->setSceneRect(sceneRect); //image.rect());

    //ui->imgMain->fitInView (scene->itemsBoundingRect(), Qt::KeepAspectRatio); //ui->imgMain->width (), ui->imgMain->height ());
    ui->imgMain->setScene(scene);
}
L.W.
  • 11
  • 3
  • 1
    [`image.scaled()`](https://doc.qt.io/qt-5/qpixmap.html#scaled-1) returns a _copy_ of the image. It doesn't modify the existing one. So at minimum you'd need `image = image.scaled(...);`. Also you can get the view size with `QRectF sceneRect(ui->imgMain->viewport()->contentsRect())` (instead of `imgMain->sceneRect();`) which may be more accurate depending on what the initial state of the `scene()` in the graphics view is (or if in fact it even has a scene). Ref: [QGraphicsView::sceneRect](https://doc.qt.io/qt-5/qgraphicsview.html#sceneRect-prop) – Maxim Paperno Oct 10 '19 at 12:22
  • Thanks. But what can I do to scale it after resize the window? The GV is in table-/gridlayout-mode. – L.W. Oct 11 '19 at 15:29
  • Well that changes the question somewhat. I've posted a complete example for you. – Maxim Paperno Oct 11 '19 at 18:10
  • ... and expanded the example to show usage inside a QWidget/QLayout with selectable images and scaling mode. – Maxim Paperno Oct 12 '19 at 14:25
  • Still no joy here? – Maxim Paperno Oct 15 '19 at 15:13

1 Answers1

0

Here is a basic custom QGraphicsView implementation which displays one image and keeps it sized/scaled to fit the available viewport space. Note that the image needs to be rescaled every time the viewport size changes, which is why it is simplest to reimplement the QGraphicsView itself and change the scaling in resizeEvent(). Although it could be done inside a custom QGraphicsScene instead. (Or, really, a number of other ways depending on the exact needs.)

The same technique could be used to keep a QGraphicsWidget as the root item in the scene to always take up the full space. Then a layout could be used in the widget to keep children aligned/resized/positioned/etc.

#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>

class GrpahicsImageView : public QGraphicsView
{
    Q_OBJECT
    public:
        using QGraphicsView::QGraphicsView;

    public slots:
        void setImage(const QString &imageFile)
        {
            if (m_imageFile != imageFile) {
                m_imageFile = imageFile;
                loadImage(viewport()->contentsRect().size());
            }
        }

        void setImageScaleMode(int mode)
        {
            if (m_scaleMode != Qt::AspectRatioMode(mode)) {
                m_scaleMode = Qt::AspectRatioMode(mode);
                if (m_item)
                    loadImage(viewport()->contentsRect().size());
            }
        }

        void loadImage(const QSize &size)
        {
            if (!scene())
                return;
            if (m_imageFile.isEmpty()) {
                // remove existing image, if any
                removeItem();
                return;
            }

            // Load image at original size
            QPixmap pm(m_imageFile);
            if (pm.isNull()) {
                // file not found/other error
                removeItem();
                return;
            }
            // Resize the image here.
            pm = pm.scaled(size, m_scaleMode, Qt::SmoothTransformation);
            if (createItem())
                m_item->setPixmap(pm);
        }

    protected:
        void resizeEvent(QResizeEvent *e) override
        {
            QGraphicsView::resizeEvent(e);
            if (!scene())
                return;
            // Set scene size to fill the available viewport size;
            const QRect sceneRect(viewport()->contentsRect());
            scene()->setSceneRect(sceneRect);
            // Keep the root item sized to fill the viewport and scene;
            if (m_item)
                loadImage(sceneRect.size());
        }

    private:
        bool createItem() {
            if (m_item)
                return true;
            if (!m_item && scene()) {
                m_item = new QGraphicsPixmapItem();
                scene()->addItem(m_item);
                return true;
            }
            return false;
        }

        void removeItem()
        {
            if (m_item) {
                if (scene())
                    scene()->removeItem(m_item);
                delete m_item;
                m_item = nullptr;
            }
        }

        Qt::AspectRatioMode m_scaleMode = Qt::KeepAspectRatio;
        QString m_imageFile;
        QGraphicsPixmapItem *m_item = nullptr;
};

Usage example:

#include <QApplication>
#include <QtWidgets>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QDialog d;
    d.setLayout(new QVBoxLayout);
    d.resize(350, 350);

    GrpahicsImageView *view = new GrpahicsImageView(new QGraphicsScene, &d);

    QComboBox *imgCb = new QComboBox(&d);
    imgCb->addItems({
        "./so-logo.png",
        "./se-logo.png",
        "./su-logo.png"
    });

    QComboBox *scaleCb = new QComboBox(&d);
    scaleCb->addItems({
        "IgnoreAspectRatio",
        "KeepAspectRatio",
        "KeepAspectRatioByExpanding"
    });
    QHBoxLayout *cbLayout = new QHBoxLayout;
    cbLayout->setSpacing(9);
    cbLayout->addWidget(imgCb);
    cbLayout->addWidget(scaleCb);

    d.layout()->addItem(cbLayout);
    d.layout()->addWidget(view);

    QObject::connect(imgCb, QOverload<const QString &>::of(&QComboBox::currentIndexChanged), view, &GrpahicsImageView::setImage);
    QObject::connect(scaleCb, QOverload<int>::of(&QComboBox::currentIndexChanged), view, &GrpahicsImageView::setImageScaleMode);

    view->setImageScaleMode(scaleCb->currentIndex());
    view->setImage(imgCb->currentText());

    return d.exec();
}

https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-logo.png
https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/se-logo.png
https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/su-logo.png

enter image description here

Maxim Paperno
  • 4,485
  • 2
  • 18
  • 22