Search code examples
qtqgraphicsview

QGraphicsView fitInView on view created in Design mode doesn't work


I have been struggling with the QGraphicsView and fitInView().

I have created a scene (very large), and a rectangle that must be shown on loading. But when loaded, the view is always zoomed very far out.

So I created a small test program, and the fitInView worked just fine !

After much struggle, trying to see what is wrong, I found that the only difference between my tiny test and the giant program were, the giant program was using a designer created ui.

So here is my attempt to reproduce it:

classes.h

#include <QGraphicsView>
#include <QGraphicsRectItem>

class MyView : public QGraphicsView
{
public:
    MyView(QWidget *parent = 0) : QGraphicsView(parent) {
        setBackgroundRole(QPalette::Highlight);
    }
};

class MyScene : public QGraphicsScene
{
public:
    MyScene(qreal sceneW, qreal sceneH, qreal canvasW, qreal canvasH, QObject* parent = 0) 
        : QGraphicsScene(parent) {
        setSceneRect(0.5*(canvasW - sceneW), 0.5*(canvasH - sceneH), sceneW, sceneH);
        m_background = new QGraphicsRectItem();
        m_background->setBrush(Qt::white);
        m_background->setPen(Qt::NoPen);
        m_background->setRect(0, 0, canvasW, canvasH);
        addItem(m_background);
    }
private:
    QGraphicsRectItem* m_background;
};

main.cpp

#define USING_UI

#include <QApplication>
#include "classes.h"

#ifdef USING_UI
#include <QMainWindow>
#include "ui_form.h"

namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow {
public:
    explicit MainWindow(QWidget *parent=0):QMainWindow(parent),ui(new Ui::MainWindow) {
        ui->setupUi(this);
        MyScene* s = new MyScene(2000, 1000, 500, 300);
        ui->myGraphicsView->setScene(s);
        ui->myGraphicsView->fitInView(0,0,500,300);  // with Qt::KeepAspectRatio
        // or ui->myGraphicsView->fitInView(s->items().at(0), Qt::KeepAspectRatio);
    }
private:
    Ui::MainWindow *ui;
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MainWindow w;
    w.show();
    return app.exec();
}

#else

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MyScene s(2000, 1000, 500, 300);
    MyView view;
    view.setScene(&s);
    view.show();
    view.fitInView(0,0,500,300);   // with Qt::KeepAspectRatio for pretty
    // or view.fitInView(s.items().at(0), Qt::KeepAspectRatio);
    return app.exec();
}
#endif

And form.ui contains a QGraphicsView promoted to MyView, nothing else.

The results are very different - and I can't figure out how to fix the ui version. enter image description here

What can I do so that the view created in the ui (using the Qt Designer) to "fit in view" the rectangle or object I suggest at startup ?

I find it very odd that

qDebug() << s->sceneRect();
qDebug() << ui->myGraphicsView->mapToScene(s->sceneRect().toRect()).boundingRect();
qDebug() << ui->myGraphicsView->mapFromScene(s->sceneRect()).boundingRect();

all display the same thing, and the

QTransform t = ui->myGraphicsView->viewportTransform();

is unity.

Perhaps I could find a way to set this transform manually - based on the viewport's actual coordinates - but I don't know how - or what will happen if later the form changes size.


Solution

  • I found the answer to my question in this answer.

    Placed the fitInView call inside the class' showEvent.

    protected:
        virtual void showEvent(QShowEvent *event) {
            if(m_startUp)
            {
                ui->myGraphicsView->fitInView(s->items().at(0), Qt::KeepAspectRatio);
                // or, either works fine:
                // ui->myGraphicsView->fitInView(0,0,500,300, Qt::KeepAspectRatio);
                m_startUp = false;
            }
            QMainWindow::showEvent(event);
        }
    

    I added the m_startUp because after zoom and minimize, restore would perform the fitInView...

    The only alternative I found was finding some values to use in fitInView based on the UI geometry, by trial and error... It did not seem like a good option.