Scale QGraphicsItem About an Arbitrary Point - qt

I'm trying to scale an object about the mouse cursor. I'm getting the mouse position easily enough, and I can scale the object no problem using item->setScale(n). However, I'm not sure how to actually incorporate the translation to account for the arbitrary point.
Is there a way to set the scale center? If not, how should I go about doing this?
This is what I have so far for my zoom in:
center = this->mapFromParent(center);
qDebug() << center;
this->setTransformOriginPoint(center);
QTransform transform;
transform = transform.scale(transform.m11() * 1.05, transform.m22() * 1.05);
this->setTransform(transform, true);
this->setTransformOriginPoint(0, 0);

Take a look at QGraphicsItem::setTransformOriginPoint(). It takes the position in item coordinates, so you'll probably have to map the mouse position to item coordinates.
I think this seems to be working as you expect:
class Scene : public QGraphicsScene
{
public:
QGraphicsItem* item;
Scene(QObject* parent = nullptr)
: QGraphicsScene(parent)
{
setSceneRect(0, 0, 500, 500);
item = addRect(200, 200, 100, 100, QPen(Qt::black), QBrush(Qt::red));
}
void wheelEvent(QGraphicsSceneWheelEvent* event)
{
/*Scale 0.2 each turn of the wheel (which is usually 120.0 eights of degrees)*/
qreal scaleFactor = 1.0 + event->delta() * 0.2 / 120.0;
item->setTransformOriginPoint(item->mapFromScene(event->scenePos()));
item->setScale(item->scale() * scaleFactor);
}
};
int main(int argc, char ** argv)
{
QApplication a(argc, argv);
Scene* scene = new Scene;
QGraphicsView view(scene);
view.resize(600, 600);
view.show();
return a.exec();
}

Related

QGraphicsItem::itemChange notified for position change but not for size change

I've got a class derived from QGraphicsEllipseItem in which I need to know when its position or size changes in any way. I handle resizing with a mouse and calls to QGraphicsEllipse::setRect.
OK, so I dutifully overrode the itemChange() method in the class and then was careful to set the ItemSendsGeometryChanges flag after creating it
// Returns a human readable string for any GraphicsItemChange enum value
inline std::string EnumName(QGraphicsItem::GraphicsItemChange e);
// Simple test ellipse class
class MyEllipse : public QGraphicsEllipseItem
{
public:
MyEllipse(int x, int y, int w, int h) : QGraphicsEllipseItem(x, y, w, h)
{
setFlags(
QGraphicsItem::ItemIsSelectable
| QGraphicsItem::ItemIsMovable
| QGraphicsItem::ItemSendsGeometryChanges);
}
// QGraphicItem overrides
virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override
{
std::stringstream oss;
oss << "ItemChange " << EnumName(change) << std::endl;
OutputDebugString(oss.str().c_str());
return __super::itemChange(change, value);
}
};
My main code creates one of these, adds it to the scene and then tries moving/resizing it.
And while I do always receive notifications after calling setPos() on the ellipse, I get NO notification after calling setRect(). I can use setRect to completely change the ellipse's geometry but my itemChange override is never called. Not with any flags.
Now obviously changing the item's rect is changing its geometry, so what am I missing?
Is there some other flag I should set? Some other way to change the size of the ellipse I should use? Some other notification virtual I can override?
The problem is that QGraphicsItem's position is not related with QGraphicsEllipseItem's rectangle. The first one is a position of the item relative to it's parent item or, if it is NULL, to it's scene. The last one is a rectangle relative to the item position where an ellipse should be drawn. The scene and QGraphicsItem's core don't know about any changes of it.
Let's take a look at this test:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QGraphicsScene scene;
QGraphicsView view(&scene);
QGraphicsEllipseItem item(10, 20, 30, 40);
scene.addItem(&item);
qDebug() << item.pos() << item.scenePos() << item.boundingRect();
item.setRect(110, 120, 30, 40);
qDebug() << item.pos() << item.scenePos() << item.boundingRect();
view.resize(500, 500);
view.show();
return app.exec();
}
Output is:
QPointF(0,0) QPointF(0,0) QRectF(9.5,19.5 31x41)
QPointF(0,0) QPointF(0,0) QRectF(109.5,119.5 31x41)
Possible ways out:
use setTransform. Transform matrix changes are tracked by standard QGraphicsitems, and itemChange will receive corresponding change. But I guess that non-ident matrices can decrease performance (didn't check).
implement your own function like setRect in which you will track geometry changes manually.
subclass QGraphicsItem, not QGraphicsEllipseItem. In this case you can prevent untrackable geometry changes as they are performed through your rules. It looks like this:
class EllipseItem: public QGraphicsItem
{
public:
// Here are constructors and a lot of standard things for
// QGraphicsItem subclassing, see Qt Assistant.
...
// This method is not related with QGraphicsEllipseItem at all.
void setRect(const QRectF &newRect)
{
setPos(newRect.topLeft());
_width = newRect.width();
_height = newRect.height();
update();
}
QRectF boundingRect() const override
{
return bRect();
}
void paint(QPainter * painter, const QStyleOptionGraphicsItem * option,
QWidget * widget = nullptr) override
{
painter->drawRect(bRect());
}
private:
qreal _width;
qreal _height;
QRectF bRect() const
{
return QRectF(0, 0, _width, _height);
}
};
You also should track item transformations and moves through QGraphicsItem::itemChange.

Programmatic scrolling with QGraphicsView and QGraphicsItem?

I would like to programmatically scroll a scene to the left / right, but I am not sure how to do that properly. Note that I do not want to have (visible) scroll bars.
I use a standard QGraphicsView + QGraphicsScene + QGraphicsItem setup. I have downsized it to the minimum, with one single QGraphicsItem (a QGraphicsRectItem) in the scene.
I have managed to achieve programmatic scrolling by setting my view like this:
// view setup
view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
and then, in another part of the code:
// programmatic scrolling
QScrollBar* const sb = view->horizontalScrollBar();
sb->setRange(0, 1000); // some values for experimenting
sb->setValue(sb->value() + 100 or -100); // some increment for experimenting
This works, but... scrolling through invisible scrollbars doesn't feel right.
I tried this more straightforward approach:
// programmatic scrolling - doesn't quite work
view->viewport()->scroll(100 or -100, 0); // some increment for experimenting
This code does scroll, but when the rectangle goes off the left edge of the view, and I reverse the scrolling direction (increment changed from 100 to -100 in the call to scroll()), the uncovered part of the rectangle is not repainted. The reason is that QGraphicsRectItem::paint() is not called in that case (it is called when using the scrollbar method).
So, is there a way to get viewport()->scroll() work? Or some other simple way to achieve programmatic scrolling? Or is the artificial scrollbar method just the way to go?
Moving the view assumes that it's smaller than its scene. If they're the same size, it won't move.
QGraphicsView can be set to centerOn any position in scene coordinates. Use a timer to call centerOn to move the view one frame at a time.
Here's a working example: -
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QTimer>
class MyView : public QGraphicsView
{
private:
public:
MyView(QGraphicsScene* pScene)
: QGraphicsView(pScene, NULL)
{}
void AnimateBy(int x)
{
float updateFrequency = (1000/30.0); // ~30 frames per second
QPointF currScenePos = sceneRect().center();
int curX = currScenePos.x();
int endPos = curX + x;
int distanceToAnimate = (endPos - curX);
// speed = dist / time
float updatePosInterval = (float)distanceToAnimate / updateFrequency;
printf("updatePosInterval: %f \n", updatePosInterval);
static float newXPos = sceneRect().center().x();
QTimer* pTimer = new QTimer;
QObject::connect(pTimer, &QTimer::timeout, [=](){
newXPos += updatePosInterval;
centerOn(newXPos, sceneRect().center().y());
// check for end position or time, then....
if(newXPos >= endPos)
{
pTimer->stop();
pTimer->deleteLater();
}
});
pTimer->start(updateFrequency);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene scene(0, 0, 10000, 20000);
MyView* view = new MyView(&scene);
QGraphicsRectItem* pRect = new QGraphicsRectItem(0, 0, 100, 100);
pRect->setPos(scene.width()/2, scene.height()/2);
scene.addItem(pRect);
// timer to wait for the window to appear, before starting to move
QTimer* pTimer = new QTimer;
pTimer->setSingleShot(true);
QObject::connect(pTimer, &QTimer::timeout,[=](){
view->centerOn(pRect); // centre on the rectangle
view->AnimateBy(100);
pTimer->deleteLater();
});
pTimer->start(1000);
view->show();
return a.exec();
}
So, we create the animation by moving the view frame-by-frame using the call to centerOn.
For simplicity, the code just deals with moving in one axis. To move in 2 axis, use 2D vector maths to calculate the interval position.
Try to change the view transformation with the QGraphicsView::translate() or QGraphicsView::setTransform().
But keep in mind that you can't move the viewport "outside" the scene, so make sure that your scene rectangle is large enough.
If I got your question correctly, there is a dojo classes library with such class as PanWebView that allow QWebView to scroll smoothly with mouse without any scrollbars. Take a look at sources. It supports panning and can be suitable for mobile apps, but maybe it'll help you too.
PanWebView class looks like this
#include <QWebView>
#include <QWebFrame>
#include <QMouseEvent>
#include <QApplication>
class PanWebView : public QWebView
{
Q_OBJECT
private:
bool pressed;
bool scrolling;
QPoint position;
QPoint offset;
QList<QEvent*> ignored;
public:
PanWebView(QWidget *parent = 0): QWebView(parent), pressed(false), scrolling(false) {
QWebFrame *frame = page()->mainFrame();
frame->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
frame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
}
protected:
void mousePressEvent(QMouseEvent *mouseEvent) {
if (ignored.removeAll(mouseEvent))
return QWebView::mousePressEvent(mouseEvent);
if (!pressed && !scrolling && mouseEvent->modifiers() == Qt::NoModifier)
if (mouseEvent->buttons() == Qt::LeftButton) {
pressed = true;
scrolling = false;
position = mouseEvent->pos();
QWebFrame *frame = page()->mainFrame();
int x = frame->evaluateJavaScript("window.scrollX").toInt();
int y = frame->evaluateJavaScript("window.scrollY").toInt();
offset = QPoint(x, y);
QApplication::setOverrideCursor(Qt::OpenHandCursor);
return;
}
return QWebView::mousePressEvent(mouseEvent);
}
void mouseReleaseEvent(QMouseEvent *mouseEvent) {
if (ignored.removeAll(mouseEvent))
return QWebView::mouseReleaseEvent(mouseEvent);
if (scrolling) {
pressed = false;
scrolling = false;
QApplication::restoreOverrideCursor();
return;
}
if (pressed) {
pressed = false;
scrolling = false;
QMouseEvent *event1 = new QMouseEvent(QEvent::MouseButtonPress,
position, Qt::LeftButton,
Qt::LeftButton, Qt::NoModifier);
QMouseEvent *event2 = new QMouseEvent(*mouseEvent);
ignored << event1;
ignored << event2;
QApplication::postEvent(this, event1);
QApplication::postEvent(this, event2);
QApplication::restoreOverrideCursor();
return;
}
return QWebView::mouseReleaseEvent(mouseEvent);
}
void mouseMoveEvent(QMouseEvent *mouseEvent) {
if (scrolling) {
QPoint delta = mouseEvent->pos() - position;
QPoint p = offset - delta;
QWebFrame *frame = page()->mainFrame();
frame- >evaluateJavaScript(QString("window.scrollTo(%1,%2);").arg(p.x()).arg(p.y()));
return;
}
if (pressed) {
pressed = false;
scrolling = true;
return;
}
return QWebView::mouseMoveEvent(mouseEvent);
}
};
And usage:
PanWebView web;
web.setUrl(QUrl("http://news.google.com"));
web.setWindowTitle("Web View - use mouse to drag and pan around");
web.show();
Also did you check this and this topics? I think it can be usefull.

QGraphicsRectItem member of a custom scene class added on mouse action gives error

I want to somehow paint a selection rectangle on scene, to show selected items (not he item bounding rectangle, but the bounding rectangle mapped to scene - and if multiple selection, the selection bounding rectangle).
I would like to try something like, on mouse press, to show the rectangle (and update based on current selection), and on mouse release, to hide it.
I am having trouble keeping the rectangle on the scene, and on mouse release it may be removing it, or maybe it was never there - and I get an error:
QGraphicsScene::removeItem: item 0x37828's scene (0x0) is different from this scene (0x1f57b68)
(The above error, and the fact that the item doesn't stay after mouse press, makes me think that it is not added properly but I don't understand why).
Here is a little sample code:
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsRectItem>
class MyScene : public QGraphicsScene
{
public:
MyScene(qreal x, qreal y, qreal w, qreal h) {
setSceneRect(x, y, w, h);
m_selectionRectangle = new QGraphicsRectItem(0,0,1,1);
m_selectionRectangle->setBrush(Qt::magenta);
m_selectionRectangle->setOpacity(0.2);
}
~MyScene() {
if(m_selectionRectangle)
delete m_selectionRectangle;
}
protected:
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) {
QGraphicsScene::mousePressEvent(event);
if(!selectedItems().isEmpty()) {
QRectF selectionRect = QRectF();
foreach(QGraphicsItem* item, selectedItems())
selectionRect |= item->mapToScene(item->boundingRect()).boundingRect();
m_selectionRectangle->setRect(selectionRect);
addItem(m_selectionRectangle);
}
}
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
QGraphicsScene::mouseReleaseEvent(event);
removeItem(m_selectionRectangle);
}
private:
QGraphicsRectItem* m_selectionRectangle;
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MyScene* s = new MyScene(0, 0, 800, 600);
QGraphicsView view(s);
view.setDragMode(QGraphicsView::RubberBandDrag);
view.show();
QGraphicsRectItem* xxx = new QGraphicsRectItem(200, 200, 100, 100);
QGraphicsEllipseItem* yyy = new QGraphicsEllipseItem(300, 300, 200, 100);
s->addItem(xxx);
s->addItem(yyy);
xxx->setFlags(QGraphicsItem::ItemIsMovable|QGraphicsItem::ItemIsFocusable|QGraphicsItem::ItemIsSelectable);
yyy->setFlags(QGraphicsItem::ItemIsMovable|QGraphicsItem::ItemIsFocusable|QGraphicsItem::ItemIsSelectable);
return app.exec();
}
What is the meaning of that error, what am I doing wrong in adding the selection rectangle, and why doesn't it stay there - and how can I fix it ?
The meaning of the error is literal: you're passing an item to removeItem that is not a child item of the scene you're trying to remove it from. It is nonsense to remove an item that is not in the scene to start with.
There is nothing that guarantees that the selection rectangle is on the scene when the mouse button is released, since there are paths through mousePressEvent that don't add the rectangle to the scene. I'm not even sure if you are guaranteed to get a press event preceding each release event at all.
You have to only remove the rectangle if it's on the scene (and virtual is not needed, but Q_DECL_OVERRIDE is!):
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) Q_DECL_OVERRIDE {
QGraphicsScene::mouseReleaseEvent(event);
if (m_selectionRectangle.scene()) removeItem(m_selectionRectangle);
}
Also, the destructor of your custom scene is unnecessary. Simply add the item by value:
class MyScene : public QGraphicsScene
{
QGraphicsRectItem m_selectionRectangle;
public:
MyScene(qreal x, qreal y, qreal w, qreal h) :
m_selectionRectangle(0, 0, 1 1)
{
setSceneRect(x, y, w, h);
m_selectionRectangle.setBrush(Qt::magenta);
m_selectionRectangle.setOpacity(0.2);
}
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event) Q_DECL_OVERRIDE {
...
}
...
};

Why do I see gaps between pixmap tiles in QGraphicsView when I enable Antialiasing

I am using QGraphicsView framework to display a big image from smaller QPixmap tiles. I also want to enable Antialiasing since the scene will contain line items. Why do I see gaps between the tiles when I enable Antialiasing?
class MainWindow : public QWidget
{
public:
MainWindow(QWidget *parent = 0);
protected:
void resizeEvent(QResizeEvent*);
private:
QGraphicsScene* _scene;
QGraphicsView* _view;
qreal _scale;
static const int _imageWidth = 512;
static const int _imageHeight = 128;
};
MainWindow::MainWindow(QWidget *parent)
: QWidget(parent)
{
_scene = new QGraphicsScene(this);
_view = new QGraphicsView(_scene, this);
//this causes gaps to appear ?
_view->setRenderHints(QPainter::Antialiasing);
_scene->setBackgroundBrush( QBrush( QColor( Qt::lightGray ) ) );
QHBoxLayout *layout = new QHBoxLayout(this);
layout->addWidget(_view);
setWindowTitle(QString("GapsBetweenTiles- QT Version %1")
.arg(QT_VERSION_STR));
QImage img = QImage(_imageWidth, _imageHeight, QImage::Format_RGB32);
img.fill(QColor(00, 50, 50));
int offset = 0;
for (int k=0; k < 10; ++k) {
QGraphicsPixmapItem* pixitem = _scene->addPixmap(
QPixmap::fromImage(img));
pixitem->setTransformationMode(Qt::SmoothTransformation);
pixitem->setPos(0, offset);
offset += _imageHeight;
}
_scale = 1.0;
}
void MainWindow::resizeEvent(QResizeEvent* )
{
int scaledWidth = (qreal)_view->width() -
_view->verticalScrollBar()->width() ;
qreal scale = (qreal)scaledWidth / (qreal)_imageWidth;
qreal scaleMult = scale / _scale;
_view->scale(scaleMult, scaleMult);
_scale = scale;
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
The gaps appear when scaled image height (_imageHeight * scale) becomes fractional.
Each QGraphicsPixmapItem is drawn as a separate object. If such object has fractional height the border is smoothed when anti-aliasing enabled (fractional bordering line is partially painted).
There are three possible gap layouts in your case:
no gaps if scaled image height is integer
periodic series of 1 object with gap and 1 without gap if fractional part of height is 0.5
periodic series of 3 objects with gaps and 1 object without gap if fractional part is 0.25 or 0.75; here the 2nd gap is brighter than the 1st and 3rd gaps.
So, if you want perfect object alignment the scaled height should be integer.
In your example the scaled height is integer when scaled width is divisible by 4.
It can be verified by adding into resizeEvent the following line:
scaledWidth = (scaledWidth / 4) * 4;
By the way, you can disable anti-aliasing only for QGraphicsPixmapItem objects by removing the line:
pixitem->setTransformationMode(Qt::SmoothTransformation);

QGraphicsItem setShear ? (applicable for single or multiple items)

To apply rotation on a QGraphicsItem, I can either call rotate() or setRotation(). What I see happening:
item.rotate(angle);
results in rotation, as I expect; yet if I copy the item (using a cop constructor in a subclass), no rotation will be copied (even if I copy all transformations).
item.setRotation(angle);
results in the item having a rotation() property which I can copy - but requires an update.
So the second version is what I need.
I would like to be able to apply shear to my items as well.
item.shear(shx, shy);
looks good on initial item - but I cannot find a way to copy this shear. Nor can I find a similar property as for rotation: there is no setShear() that I can find.
Even more, if I try to play with transformations, to achieve a group shear (like this question's rotation), I get very weird results...
How can I create a similar stored property for shear ?
Edit:
Trying
QTransform t;
t.shear(shx, shy);
item->setTransform(t, true);
also gives me a giant scaling and some rotation... I have tried to divide shx and shy by 100 and it seems reasonable (not sure if correct ?).
Note - will move the code snippet in answer, since it seems it will work.
It seems that I have to divide shear factors by 100 (this doesn't seem true always).
void shearItem(qreal shx, qreal shy)
{
QRectF rect;
foreach(QGraphicsItem* item, scene()->selectedItems())
rect |= item->mapToScene(item->boundingRect()).boundingRect();
QPointF center = rect.center();
QTransform t;
t.translate(center.x(), center.y());
// seems shear increases item to gigantic proportions so I tried
t.shear(shx/100, shy/100);
t.translate(-center.x(), -center.y());
foreach(QGraphicsItem* item, scene()->selectedItems())
{
item->setPos(t.map(item->pos()));
item->setTransform(t, true);
}
}
I think the transformations are combined on item, so I don't need to do any action to combine any rotation or scaling or shear... I can just use
item->setTransform(t, true);
for all transforms so there is no need to separately set rotation or scale.
There does not seem to exist any conflict though between translate(), rotate(), scale() and shear() methods and setting the transform matrix. So combining these functions, and then copying the transform seems fine. (http://doc.qt.io/qt-4.8/qtransform.html#setMatrix).
There does not seem to be any documented reason for having to scale down the shear factors... (http://doc.qt.io/qt-4.8/qtransform.html#shear).
If I set shear in item constructor, it works without having to divide by 100.
Yet if I call a shear as in code above, without scaling the factors down I get a resize as well. I find this very confusing... But as long as it works....
Full sample code: included rotation change and shear change
myview.h
#ifndef MYVIEW_H
#define MYVIEW_H
#include <QGraphicsView>
#include <QAction>
#include <QContextMenuEvent>
#include <QGraphicsItem>
class MyView : public QGraphicsView
{
Q_OBJECT
public:
MyView(QWidget *parent = 0);
protected:
virtual void contextMenuEvent(QContextMenuEvent *event);
private slots:
void rotateItem(qreal deg = 10);
void shearItem(qreal shx = 10, qreal shy = 10);
private:
void createActions();
QAction *rotateAct;
QAction *shearAct;
};
#endif // MYVIEW_H
myview.cpp
#include "myview.h"
#include <QMenu>
MyView::MyView(QWidget *parent) : QGraphicsView(parent)
{
createActions();
setScene(new QGraphicsScene(-500, -150, 1000, 600, this));
setDragMode(RubberBandDrag);
}
void MyView::contextMenuEvent(QContextMenuEvent *event)
{
QGraphicsItem* item = itemAt(event->pos());
if(item != NULL)
item->setSelected(true);
if(scene()->selectedItems().isEmpty()) return;
QMenu menu(this);
menu.addAction(rotateAct);
menu.addAction(shearAct);
menu.exec(event->globalPos());
}
void MyView::rotateItem(qreal deg)
{
QRectF rect;
foreach(QGraphicsItem* item, scene()->selectedItems())
rect |= item->mapToScene(item->boundingRect()).boundingRect();
QPointF center = rect.center();
QTransform t;
t.translate(center.x(), center.y());
t.rotate(deg);
t.translate(-center.x(), -center.y());
foreach(QGraphicsItem* item, scene()->selectedItems())
{
item->setPos(t.map(item->pos()));
item->setRotation(item->rotation() + deg);
}
}
void MyView::shearItem(qreal shx, qreal shy)
{
QRectF rect;
foreach(QGraphicsItem* item, scene()->selectedItems())
rect |= item->mapToScene(item->boundingRect()).boundingRect();
QPointF center = rect.center();
QTransform t;
t.translate(center.x(), center.y());
t.shear(shx, shy);
// seems shear increases item to gigantic proportions so I tried
//t.shear(shx/100, shy/100);
t.translate(-center.x(), -center.y());
foreach(QGraphicsItem* item, scene()->selectedItems())
{
item->setPos(t.map(item->pos()));
item->setTransform(t, true);
}
}
void MyView::createActions()
{
rotateAct = new QAction(tr("Rotate 10 degrees"), this);
connect(rotateAct, SIGNAL(triggered()), this, SLOT(rotateItem()));
shearAct = new QAction(tr("Shear 10, 10"), this);
connect(shearAct, SIGNAL(triggered()), this, SLOT(shearItem()));
}
main.cpp:
#include <QtGui>
#include "myview.h"
int main( int argc, char **argv )
{
QApplication app(argc, argv);
MyView* view = new MyView();
QGraphicsRectItem* rItem = view->scene()->addRect(30, 40, 100, 100, Qt::NoPen, Qt::blue);
QGraphicsRectItem* rItem1 = view->scene()->addRect(-30, -40, 100, 100, Qt::NoPen, Qt::red);
QGraphicsEllipseItem* eItem = view->scene()->addEllipse(70, -50, 100, 100, Qt::NoPen, Qt::blue);
foreach(QGraphicsItem* item, view->scene()->items())
{
item->setFlag(QGraphicsItem::ItemIsMovable);
item->setFlag(QGraphicsItem::ItemIsFocusable);
item->setFlag(QGraphicsItem::ItemIsSelectable);
}
view->show();
return app.exec();
}

Resources