QGraphicsView
, QGraphicScene
and QGraphicsItem
provide a way for applications based on Qt Widgets to show 2D graphics.
Note
The source code can be found on the Git repository under the Chapter01-graphicsview
directory, in the cp1
branch.
Every QGraphicsView
needs a QGraphicsScene
. Every QGraphicsScene
needs one or more QGraphicsItem
.
QGraphicsItem
can be any of the following:
QGraphicsEllipseItem
QGraphicsLineItem
QGraphicsLineItem
QGraphicsPathItem
QGraphicsPixmapItem
QGraphicsPolygonItem
QGraphicsRectItem
QGraphicsSimpleTextItem
QGraphicsTextItem
Qt Designer has support for adding QGraphicsView
. You can follow these steps to do so:
- Drag the
QGraphicsView
to a new application form and fill the form with aQGridLayout
like we did before.
- Implement a
QGraphicsScene
in the source code and add it to theQGraphicsView
QGraphicsScene *gScene=newQGraphicsScene(this); ui->graphicsView->setScene(gScene);
gScene->setSceneRect(-50, -50, 120, 120);
- Create a red rectangle to show the bounding rectangle. To make it a red color, create a
QPen
which will be used to paint the rectangle and then add the rectangle to theScene
.
QPenpen=QPen(Qt::red); gScene->addRect(gScene->sceneRect(),pen);
- Build and run the application. You will notice an app with a red bordered square on it.
As mentioned before, QGraphicsView
shows QGraphicsItems
. If we want to add some collision detection we need to subclass QGraphicsSimpleTextItem
.
The header file for this is as follows:
#include<QGraphicsScene> #include<QGraphicsSimpleTextItem> #include<QGraphicsItem> #include<QPainter> classTextGraphic:publicQGraphicsSimpleTextItem { public: TextGraphic(constQString&text); voidpaint(QPainter*painter,constQStyleOptionGraphicsItem*option,QWidget*widget); QStringsimpleText; };
This custom class derived from QGraphicsSimpleTextItem
will reimplement the paint(..)
function, and use the collidingItems(...)
function ofscene
to detect when something collides with our text object. Normally, collidingItems
will return a QList
of QGraphicsItems
, but here it is just used to detect if any items are colliding.
Since this class holds only one item, it is known which item it is. If a collision is detected, the text changes. We don't need to check if the item's text is different before we change it, as the parent class's setText(...)
does that for us.
TextGraphic::TextGraphic(constQString&text) :QGraphicsSimpleTextItem(text), simpleText(text) { } voidTextGraphic::paint(QPainter*painter,constQStyleOptionGraphicsItem*option,QWidget*widget) { if(scene()->collidingItems(this).isEmpty()) QGraphicsSimpleTextItem::setText("BOOM!"); else QGraphicsSimpleTextItem::setText(simpleText); QGraphicsSimpleTextItem::paint(painter, option, widget); }
Now create our TextGraphic
object and add it to the Scene
to use.
TextGraphic*text=newTextGraphic(QStringLiteral("QtMobile!")); gScene->addItem(text);
If you build and run this, notice the text
object will not move if we try to drag it around. QGraphicsItems
have a flag
property called QGraphicsItem::ItemIsMovable
that can be set to allow it to be moved around, either by the user or programmatically:
text->setFlag(QGraphicsItem::ItemIsMovable);
When we build and run this, you can grab the text
object and move it around. If it goes beyond our bounding rectangle, it will change text, only returning to the original text if it moves inside the red box again.
If you wanted to animate this, just throw in a timer and change the text
object's position when the timer fires.
Even with Qt Quick's software renderer, QGraphicsView
is still a viable solution for graphics animation. If the target device's storage space is really tight, there might not be enough space to add Qt Quick libraries. Or a legacy app might be difficult to import to Qt Quick.