QGraphics Confusion (Differences between QT4 / QT5)
-
I saw an old example of using QGraphics. The example is from 2007 so it doesn't seem to work with the actual Qt5 Version. I couln't find a documentation of the old interface.
The old example is like this:
int main( int argc, char **argv ) { QApplication app( argc, argv ); QGraphicsScene scene( 0, 0, 200, 200 ); QGraphicsRectItem *rectItem = new QGraphicsRectItem( QRect( 10, 10, 50, 100 ), 0, &scene ); QGraphicsView view; view.setScene( &scene ); view.show(); return app::excec(); }
Now it looks like the constructor of
QGraphicsRectItem
does not has this constructor anymore. It doesn't seem to be possible to add the scene in it . Instead i usedscene.addItem
like this:int main(int argv, char** argc) { QApplication app{argv, argc}; QGraphicsScene scene{QRect{0, 0, 200, 200}}; auto rectItem = new QGraphicsRectItem{QRect{10, 10, 50, 100}}; scene.addItem(rectItem); QGraphicsView view; view.setScene(&scene); view.show(); return QApplication::exec(); }
Now why do i ask all this if I found a workarround? There is annother bigger example here:
https://github.com/Apress/foundations-of-qt-dev/tree/master/Chapter07/graphicsview/interaction
It creates a Ellipse and a Square on the Screen. These can be resized or moved by special designed handles. See the 3 files in the link.
I rewrote it to QT5 but i have two issues:
I can only move the single handles. Not all Handles and the Circle or Ellipse are moved / resized.
My code looks like this:
int main(int argv, char** argc) { QApplication app{argv, argc}; QGraphicsScene scene{QRect{0, 0, 200, 200}}; auto rectItem = new QGraphicsRectItem{QRect{10, 10, 50, 100}}; auto elItem = new QGraphicsEllipseItem{QRect{80, 40, 100, 80}}; auto trh = new HandleItem(rectItem, Qt::red, HandleItem::Role::Top); auto rrh = new HandleItem(rectItem, Qt::red, HandleItem::Role::Right); auto crh = new HandleItem(rectItem, Qt::red, HandleItem::Role::Center, QList<HandleItem*>{trh, rrh}); auto teh = new HandleItem(elItem, Qt::green, HandleItem::Role::Top); auto reh = new HandleItem(elItem, Qt::green, HandleItem::Role::Right); auto ceh = new HandleItem(elItem, Qt::green, HandleItem::Role::Center, QList<HandleItem*>{teh, reh}); scene.addItem(rectItem); scene.addItem(elItem); scene.addItem(trh); scene.addItem(rrh); scene.addItem(crh); scene.addItem(teh); scene.addItem(reh); scene.addItem(ceh); QGraphicsView view; view.setScene(&scene); view.show(); return QApplication::exec(); }
#ifndef HANDLEITEM_H #define HANDLEITEM_H #include <QGraphicsItem> class HandleItem : public QGraphicsItem { public: enum class Role { Center, Right, Top }; HandleItem(QGraphicsItem *item, QColor color, Role role = Role::Center, QList<HandleItem*> handles = QList<HandleItem*>{}); QRectF boundingRect() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; protected: void mousePressEvent(QGraphicsSceneMouseEvent *event) override; void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; QVariant itemChange( GraphicsItemChange change, const QVariant &value) override; private: QGraphicsItem *mItem; Role mRole; QColor mColor; QList<HandleItem*> mHandles; bool mPressed{false}; }; #endif // HANDLEITEM_H
#include "handleitem.h" #include <QPainter> #include <QTransform> HandleItem::HandleItem( QGraphicsItem *item, QColor color, HandleItem::Role role, QList<HandleItem *> handles) : QGraphicsItem{}, mItem{item}, mRole{role}, mColor{color}, mHandles{handles} { setZValue(100); setFlag(ItemIsMovable); } QRectF HandleItem::boundingRect() const { auto point = mItem->boundingRect().center(); switch(mRole) { case Role::Center: return QRectF(point-QPointF{5, 5}, QSize{10, 10}); case Role::Right: point.setX(mItem->boundingRect().right()); return QRectF(point-QPointF{3, 5}, QSize{6, 10}); case Role::Top: point.setY(mItem->boundingRect().top()); return QRectF(point-QPointF{5, 3}, QSize{10, 6}); } return QRectF{}; } void HandleItem::paint( QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) { painter->setPen(mColor); painter->setBrush(mColor); auto rect = boundingRect(); QVector<QPointF> points; switch(mRole) { case Role::Center: painter->drawEllipse(rect); break; case Role::Right: points.push_back(rect.center()+QPointF{3, 0}); points.push_back(rect.center()+QPointF{-3, -5}); points.push_back(rect.center()+QPointF{-3, 5}); painter->drawConvexPolygon(QPolygonF{points}); break; case Role::Top: points.push_back(rect.center()+QPointF{0, -3}); points.push_back(rect.center()+QPointF{-5, 3}); points.push_back(rect.center()+QPointF{5, 3}); painter->drawConvexPolygon(QPolygonF{points}); break; } } void HandleItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { mPressed = true; QGraphicsItem::mousePressEvent(event); } void HandleItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { mPressed = false; QGraphicsItem::mousePressEvent(event); } QVariant HandleItem::itemChange( QGraphicsItem::GraphicsItemChange change, const QVariant &value) { if(change == ItemPositionChange && mPressed) { auto movement = value.toPoint() - pos(); auto center = mItem->boundingRect().center(); switch(mRole) { case Role::Center: { mItem->moveBy(movement.x(), movement.y()); QTransform transform; transform.translate(movement.x(), movement.y()); for(auto& handle : mHandles) { handle->setTransform(transform); } } break; case Role::Right: { if(-2*movement.x() + mItem->sceneBoundingRect().width() <= 5){ return QGraphicsItem::itemChange(change, pos()); } movement.setY(0); QTransform transform; transform.translate(center.x(), center.y()); transform.scale( 1.0 + 2.0*movement.x() / mItem->sceneBoundingRect().width(), 1); transform.translate(-center.x(), -center.y()); mItem->setTransform(transform); } break; case Role::Top: { if(-2*movement.y() + mItem->sceneBoundingRect().height() <= 5){ return QGraphicsItem::itemChange(change, pos()); } movement.setX(0); QTransform transform; transform.translate(center.x(), center.y()); transform.scale( 1, 1.0-2.0*movement.y() / mItem->sceneBoundingRect().height()); transform.translate(-center.x(), -center.y()); mItem->setTransform(transform); } break; } return QGraphicsItem::itemChange( change, pos()+movement ); } return QGraphicsItem::itemChange(change, value); }
From my understanding i add the ellipse, the rectangle and the handles into the scene. Also I add the pointers for the ellipse and the rectangle to the handles.
In the handles the ellipse / rectangle is accesed and modified via the handles. Then why the modification is not drawn in the scene as expected?I would be gratefull if you can give me some hint.