In the
first article I told how I could about the merits of the framework. Today I will try to tell about his dark side, poorly lit in the documentation.
Case number 1
We want to resize the scene and the objects in it according to the size of the displayed window. The dock says, “QGraphicsView takes ownership of the viewport widget.” Well, let's create a simplest project and write the following:
MainWindow.h:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QGraphicsScene> #include <QGraphicsEllipseItem> #include <QGraphicsView> class MainWindow : public QWidget { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: bool eventFilter(QObject *, QEvent *); private: QGraphicsScene *m_scene; QGraphicsEllipseItem *m_elipse; QGraphicsView * graphicsView; }; #endif // MAINWINDOW_H
MainWindow.cpp:
#include "MainWindow.h" #include <QGridLayout> #include <QEvent> #include <QResizeEvent> MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { setLayout(new QGridLayout()); graphicsView = new QGraphicsView(); layout()->addWidget(graphicsView); graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_scene = new QGraphicsScene(); m_elipse = new QGraphicsEllipseItem(); m_scene->addItem(m_elipse); m_scene->setSceneRect(m_elipse->boundingRect()); graphicsView->setScene(m_scene); graphicsView->installEventFilter(this); } MainWindow::~MainWindow() { } bool MainWindow::eventFilter(QObject *, QEvent *event) { if(event->type() == QEvent::Resize ) { QResizeEvent *res = reinterpret_cast<QResizeEvent*>(event); m_elipse->setRect(0, 0, res->size().width(), res->size().height()); return true; } return false; }
It is expected that by changing the size of the widget, we will change the size of the ellipse, but it will still be completely visible, since The size and display area will change. Compile, run and make sure that it doesn't work as it should: you can reduce the initial size, but when it is exceeded, the ellipse is clipped.
')
Then we change
graphicsView->installEventFilter(this);
on
graphicsView->viewport()->installEventFilter(this);
Compile, run - everything works. Now we will try to install a filter in the scene. Compile, run and see nothing at all.
Case number 2
We want to track the position of the mouse as it moves around the scene. To do this, we modify our test and class as follows:
bool MainWindow::eventFilter(QObject *, QEvent *event) { if(event->type() ==QEvent::MouseMove) { qDebug()<<event; return true; } return false; }
In the constructor we add:
graphicsView->setMouseTracking(true);
Well, install the filter in graphicsView.
We compile, run, make sure that does not work. Install the filter in the viewport and everything works again.
Now we modify a little:
if(event->type() ==QEvent::MouseMove)
replace on
if(event->type() ==QEvent::GraphicsSceneMouseMove)
And install the filter in the scene. And unlike last time, we find that the movement of the mouse is tracked.
Conclusions of the investigation
As it would be not strange from the point of view of a beginner, but the Graphics Framework really follows the logic: the display is separate, and the composition is separate. And because the resizing event is not transmitted to the scene. And graphicsView really takes care of the viewport. This can be verified if in case number 1 replace the filter with:
if(event->type() == QEvent::Resize ) { QResizeEvent *res = reinterpret_cast<QResizeEvent*>(event); m_elipse->setRect(0, 0, res->size().width(), res->size().height()); } return false;
Those. remove the event filtering, we will see the expected behavior. Those. the event was filtered and was not further transferred to the viewport. But adequate behavior when decreasing is caused by Qt's internal logic or spontaneous events, as they are called in the code.
Let's return to the transfer of events to the scene. This process is not described at all, but there is an important point: before going to the scene, graphicsView transforms the event into the corresponding QGRaphisSceneEvent, but this happens in specialized methods, which is why it is in the dock and recommends redefining them, rather than the entry point (
event or
viewportEvent ).
Once again I will pay attention to the last moment: the logic of the framework is such that all external events are prepared to work with the scene. Those. if you have your QEvent, which must be passed to the scene, then the best way, not violating Qt's logic, is to create an analogue of a custom event, inherited from QGRaphicsSceneEvent, write a transformation method and send the transformed to the scene, which will be called in the class inherited from QGraphicsView , well, send a QEvent to this most modified QGraphicsView.
It remains to consider the last stage: delivery of the event to the Item. Here, the picture is similar with delivery to the scene, namely: after the event has come, it is determined which specialized function should be activated; in this specialized function, the coordinates of the event are determined, using itemAt () methods to determine which Item to deliver the event, then the event is prepared for delivery to the Item and only after that is sent to it.
By the way, here too the rake lies. The dock says that you need to call geometryChange before changing the geometric dimensions, otherwise we stumble upon a problem with drawing. But not only problems will arise with the delivery of events.