QGraphicsScene does not fit QGraphicsView full size
-
Hello,
here is a test code.CMakeLists.txt
cmake_minimum_required(VERSION 3.5) project(test LANGUAGES CXX) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt5 COMPONENTS REQUIRED Core Widgets) set(SOURCE_FILES main.cpp test.cpp) add_executable(test ${SOURCE_FILES}) target_link_libraries(test PRIVATE Qt5::Core Qt5::Widgets)
main.cpp
// Qt headers #include <QApplication> #include "test.h" int main(int argc, char *argv[]) { QApplication application(argc, argv); Test *applicationWindow = new Test(); applicationWindow->setMinimumWidth(1200); applicationWindow->setMinimumHeight(900); applicationWindow->show(); return application.exec(); }
test.h
#ifndef TEST_H #define TEST_H #include <QMainWindow> #include <QGraphicsView> class Test : public QMainWindow { Q_OBJECT public: explicit Test(QWidget* parent = nullptr); ~Test() override; public slots: private: QGraphicsView *m_view; }; #endif // TEST_H
test.cpp
// Qt headers #include <QGraphicsView> #include <QGraphicsScene> #include <QPixmap> #include <QGraphicsPixmapItem> #include <QGraphicsRectItem> #include <QPainter> #include <QPen> // Other headers #include "test.h" Test::Test(QWidget* parent /*=nullptr*/): QMainWindow(parent) { m_view = new QGraphicsView(); // draw borders of the QGraphicsView m_view->setStyleSheet("border: 5px solid red"); //define the QGraphicsScene QGraphicsScene *scene = new QGraphicsScene(); m_view->setRenderHint(QPainter::Antialiasing, true); m_view->setScene(scene); //define a QPixmap QPixmap img("tmp.svg"); QGraphicsPixmapItem *item = scene->addPixmap(img); // image should fit all the QGraphicsScene/QGraphicsView m_view->fitInView(item, Qt::IgnoreAspectRatio); // draw borders of the QGraphicsScene QGraphicsRectItem *rect_item = scene->addRect(scene->sceneRect()); rect_item->setParentItem(item); QPen pen = QPen(Qt::black); pen.setWidth(10); rect_item->setPen(pen); m_view->show(); // set the QGraphicsView as the central widget setCentralWidget(m_view); } // destructor Test::~Test() { }
If you want to reproduce please add an image file in the directory in which you run the test program and name it tmp.svg.
Here is what I get when I run the test program
So it seems my image fits the full scene size (in black) but I do not understand my scene can fit the full QGraphicsView size (in red).
-
@odelaune
That means your scene is smaller than the view. I think you want void QGraphicsView::fitInView(const QGraphicsItem *item, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio) ?Ah, actually for the whole
scene
: void QGraphicsView::fitInView(const QRectF &rect, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio)ui->view->fitInView( scene->sceneRect(),Qt::KeepAspectRatio);
?
-
@JonB
I agree that my scene is smaller than my view but I do not understand why QGraphicsView::fitInView does not do the job.
In test.cpp, using "m_view->fitInView (scene->sceneRect(),Qt::IgnoreAspectRatio);" instead of "m_view->fitInView(item, Qt::IgnoreAspectRatio);" gives me exactly the same result, i.e. the screenshot I have given in my first post. -
@odelaune
The red square is the wholeQMainWindow
, right? Why would you expect theQGraphicsView
to occupy the whole of that, when it's only thecentralWidget
? See the picture at https://doc.qt.io/qt-6/qmainwindow.html#qt-main-window-framework. I wouldn't use aQMainWindow
if I wanted one widget to occupy the whole window. -
The red square is drawn using "m_view->setStyleSheet("border: 5px solid red");" so technically this is the border of the QGraphicsView object and indeed this object is defined as the central widget. So it is still not clear to me why the QGraphicsScene does not fit the QGraphicsView.
Since I have no toolbars, no dock, etc. (I have only one widget in my mainwindow, defined as the central widget). So everything should scale the full size of the mainwindow, but it is not.How would you rewrite my code to get what I look for?
-
Actually this code is a sample of my whole code where the QGraphicsView is inside a widget, so I experience the same issue either with QMainWindow or with QWidget.
@JonB said in QGraphicsScene does not fit QGraphicsView full size:
- Maybe your scene is already the full size of the view (or vice versa). Maybe you actually need to enlarge the scene/view to fill the whole window.
Why not but I am not sure to know how to do it.
-
@odelaune said in QGraphicsScene does not fit QGraphicsView full size:
m_view = new QGraphicsView();
m_view = new QGraphicsView( this );
QGraphicsScene *scene = new QGraphicsScene( m_view or this );
m_view->setRenderHint(QPainter::Antialiasing, true);
m_view->setScene(scene); ///The view does not take ownership of scene with this call.Try to change resize policy of scene
check this example: https://code.qt.io/cgit/qt/qtbase.git/tree/examples/widgets/graphicsview/elasticnodes?h=6.3
-
Hmmm, here is my code now
main.cpp
// Qt headers #include <QApplication> #include "test.h" int main(int argc, char *argv[]) { QApplication application(argc, argv); Test *applicationWindow = new Test(); applicationWindow->setMinimumWidth(400); applicationWindow->setMinimumHeight(400); applicationWindow->show(); return application.exec(); }
test.cpp
// Qt headers #include <QPixmap> #include <QGraphicsPixmapItem> #include <QGraphicsRectItem> #include <QPainter> #include <QPen> #include <QResizeEvent> // Other headers #include "test.h" Test::Test(QWidget* parent /*=nullptr*/): QMainWindow(parent) { m_view = new QGraphicsView(this); // draw border of the QGraphicsView m_view->setStyleSheet("border: 5px solid red"); m_scene = new QGraphicsScene(m_view); m_view->setRenderHint(QPainter::Antialiasing, true); m_view->setScene(m_scene); m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); QPixmap img("tmp.svg"); QGraphicsPixmapItem *item = m_scene->addPixmap(img); // draw border of the QGraphicsScene QGraphicsRectItem *rect_item = m_scene->addRect(m_scene->sceneRect()); rect_item->setParentItem(item); QPen pen = QPen(Qt::black); pen.setWidth(10); rect_item->setPen(pen); // set the mapView as the central widget setCentralWidget(m_view); m_view->show(); m_view->fitInView (m_scene->itemsBoundingRect(),Qt::IgnoreAspectRatio); // useless here } // destructor Test::~Test() { } void Test::resizeEvent(QResizeEvent* event) { if(!m_scene) return; QRectF bounds = m_scene->itemsBoundingRect(); m_view->fitInView(bounds, Qt::IgnoreAspectRatio); }
test.h
#ifndef TEST_H #define TEST_H #include <QMainWindow> #include <QGraphicsView> #include <QGraphicsScene> class Test : public QMainWindow { Q_OBJECT public: explicit Test(QWidget* parent = nullptr); ~Test() override; void resizeEvent(QResizeEvent* event) override; public slots: private: QGraphicsView *m_view; QGraphicsScene *m_scene; }; #endif // TEST_H
And here is what I get when I start the application:
So clearly not what I am expecting.However, I get what I want when I resize the window:
The trick is done via the resizeEvent method. But I do not understand how can I do the same in the same in the constructor. Indeed
m_view->fitInView (m_scene->itemsBoundingRect(),Qt::IgnoreAspectRatio)
does not do the job when it is placed at the end of the constructor but works fine in resizeEvent.
Any idea?
-
@odelaune
Sizes are not always set/right in constructors in Qt. For example, debug out what is returned fromm_scene->itemsBoundingRect()
for that line where you call it in the constructor, my guess is it's not the size it will end up being?Size is only "correct" when the object has been shown, since that is when Qt can calculate/set it. So it would not be surprising if you have to redo this line in every
resizeEvent
.... -
@JonB said in QGraphicsScene does not fit QGraphicsView full size:
For example, debug out what is returned from m_scene->itemsBoundingRect() for that line where you call it in the constructor, my guess is it's not the size it will end up being?
Actually, they are the same (QRectF(-5,-5 472x349)) both in the constructor and in the resizeEvent function. The value doesn't change either when I resize the window (still QRectF(-5,-5 472x349)). The same with sceneRect().
-
@odelaune
But nonetheless you still say it does work when you do thefitInView()
in theresizeEvent()
, but not in the constructor, right??Then I would basically read it as:
fitInView()
does not work "at all" in constructor before the view/scene is really shown, and that's just how it is. Assuming it's good inresizeEvent()
you have your solution now anyway? (If it's still not right very first time when shown but noresizeEvent()
is called, you can do it initially inshowEvent()
too?) -
@JonB said in QGraphicsScene does not fit QGraphicsView full size:
@odelaune
But nonetheless you still say it does work when you do thefitInView()
in theresizeEvent()
, but not in the constructor, right??Yes, it does work in
resizeEvent()
.Then I would basically read it as:
fitInView()
does not work "at all" in constructor before the view/scene is really shown, and that's just how it is.It makes sense.
Assuming it's good in
resizeEvent()
you have your solution now anyway? (If it's still not right very first time when shown but noresizeEvent()
is called, you can do it initially inshowEvent()
too?)What was missing was the implementation of
showEvent()
. This is now done and it fits well, even when not resizing.Here is the working example code
test.cpp
// Qt headers #include <QPixmap> #include <QGraphicsPixmapItem> #include <QGraphicsRectItem> #include <QPainter> #include <QPen> #include <QDebug> #include <QResizeEvent> // Other headers #include "test.h" Test::Test(QWidget* parent /*=nullptr*/): QMainWindow(parent) { m_view = new QGraphicsView(this); // draw border of the QGraphicsView m_view->setStyleSheet("border: 5px solid red"); m_scene = new QGraphicsScene(m_view); m_view->setRenderHint(QPainter::Antialiasing, true); m_view->setScene(m_scene); m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); QPixmap img("tmp.svg"); QGraphicsPixmapItem *item = m_scene->addPixmap(img); // draw border of the QGraphicsScene QGraphicsRectItem *rect_item = m_scene->addRect(m_scene->sceneRect()); rect_item->setParentItem(item); QPen pen = QPen(Qt::black); pen.setWidth(10); rect_item->setPen(pen); // set the mapView as the central widget setCentralWidget(m_view); m_view->show(); } // destructor Test::~Test() { } void Test::resizeEvent(QResizeEvent* event) { if(!m_scene) return; QRectF bounds = m_scene->itemsBoundingRect(); m_view->fitInView(bounds, Qt::IgnoreAspectRatio); } void Test::showEvent(QShowEvent* event) { if(!m_scene) return; QRectF bounds = m_scene->itemsBoundingRect(); m_view->fitInView(bounds, Qt::IgnoreAspectRatio); }
Thank you very much for your support.
-
@odelaune said in QGraphicsScene does not fit QGraphicsView full size:
What was missing was the implementation of showEvent(). This is now done and it fits well, even when not resizing.
Yes, For widgets it is
showEvent()
which is first called when it is shown. For anything "size" that is better than in constructor. -