How to resize a qgraphicsitemgroup? (Drag and drop) HELP needed
-
I've read the documentation, and gone trough some posts but sadly i haven't found any good information on how to resize a qgraphicsitemgroup by for example dragging the top left corner (like a handle).
I know that the boundingrect of qgraphicsitemgroup is determined by the size of its children and that qgraphicsitemgroup itself has no setRect method. So it must be somehow possible to drag on the edges of qgraphicsitemgroup and resize the children and just update the boundingrect of the group so it looks like you have resized the group. But i tried the last days but couldn't get anything to work.
Can may anyone hint me the right way to achieve what i need?
Thanks. <3 Have a nice dayThe green outline resembles the group and i want some handles to resize it in the scene using dragging:
(im currently only drawing the handles in the paint of the groupitem)#include "resizablegraphicsgroupitem.h" #include "qgraphicssceneevent.h" #include "qpainter.h" #include <QPen> ResizableGraphicsGroupItem::ResizableGraphicsGroupItem() { // Initialisierungen hier, falls benötigt setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable); //setOwnerItem(this); } QRectF ResizableGraphicsGroupItem::boundingRect() const { return childrenBoundingRect(); } void ResizableGraphicsGroupItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { qDebug() << "Test"; Q_UNUSED(option); Q_UNUSED(widget); painter->save(); //Malt eine Linie um das Rechteck painter->setPen(QPen(Qt::green)); painter->drawRect(boundingRect()); // DIESE GRIFFE MÖCHTE ICH IN DER ANDEREN CPP zeichen @CHAT GPT QRectF rect = boundingRect(); qreal dx = 8; // Breite des Griffs qreal dy = 8; // Höhe des Griffs qreal offset = 8; // Versatz des Griffs painter->drawRect(rect.left() - offset, rect.top() - offset, dx, dy); // Oben links painter->drawRect(rect.right() + offset - dx, rect.top() - offset, dx, dy); // Oben rechts painter->drawRect(rect.left() - offset, rect.bottom() + offset - dy, dx, dy); // Unten links painter->drawRect(rect.right() + offset - dx, rect.bottom() + offset - dy, dx, dy); // Unten rechts // Zeichnet Griffe in der Mitte jeder Seite, die zur Hälfte eingerückt sind painter->drawRect(rect.left() + rect.width() / 2 - dx / 2, rect.top() - offset / 2, dx, dy); // Oben Mitte painter->drawRect(rect.right() + offset / 2 - dx, rect.top() + rect.height() / 2 - dy / 2, dx, dy); // Rechts Mitte painter->drawRect(rect.left() + rect.width() / 2 - dx / 2, rect.bottom() + offset / 2 - dy, dx, dy); // Unten Mitte painter->drawRect(rect.left() - offset / 2, rect.top() + rect.height() / 2 - dy / 2, dx, dy); // Links Mitte //drawHandlesIfNecessary(); painter->restore(); }
I also tried drawing it in an external class but this way it added the handle only inside the boundingrect:
#include "groupitemhandlerect.h" #include "qcursor.h" #include "qgraphicsscene.h" #include "qpen.h" GroupItemHandleRect::GroupItemHandleRect() { } GroupItemHandleRect::~GroupItemHandleRect() { } void GroupItemHandleRect::drawHandles() { topLeftHandle = new QGraphicsRectItem(); //Set up pen QPen mPen; mPen.setWidth(2); mPen.setColor(Qt::black); //Top left handle QPointF topLeftCorner = ownerItem->boundingRect().topLeft() + QPointF(-8.0,-8.0); QRectF topLeftHandleRect = QRectF(topLeftCorner,QSize(8,8)); topLeftHandle->setRect(topLeftHandleRect); if(!handlesAddedToScene){ topLeftHandle->setPen(mPen); //topLeftHandle->setBrush(QBrush(Qt::black)); ownerItem->scene()->addItem(topLeftHandle); topLeftHandle->setParentItem(ownerItem); topLeftHandle->setCursor(QCursor(Qt::SizeFDiagCursor)); } handlesAddedToScene = true; } void GroupItemHandleRect::setOwnerItem(QGraphicsItem* item) { ownerItem = item; } void GroupItemHandleRect::drawHandlesIfNecessary() { if(!ownerItem){ qWarning() << "GroupItemHandleRect : No ownerItem set. Not drawing any\ handle. Please call setOwnerItem on your GroupItemHandleRect subclass"; return; } if(ownerItem->isSelected()){ drawHandles(); }else{ ownerItem->scene()->removeItem(topLeftHandle); delete(topLeftHandle); } }
-
@StudentScripter
I do not think thatQGraphicsItemGroup
offers any such functionality. I think you have to code this yourself. Have a read through e.g. https://stackoverflow.com/questions/67027190/qgraphicsitemgroup-and-childs-resize -
@JonB Well i've build something similar for a qgraphicsrectitem the problem is my approach only works when you can call setRect like this:
(haven't found a way to make this work for the graphicsitemgroup, anyone got an idea?)
Here the rectitem itself:
#ifndef RESIZABLEPIXMAPITEM_H #define RESIZABLEPIXMAPITEM_H #include <QGraphicsRectItem> #include "resizablehandlerect.h" #include "MyObjectTypes.h" class ResizablePixmapItem : public QGraphicsRectItem, public ResizableHandleRect { public: explicit ResizablePixmapItem(QPixmap pixmap); //QRectF InitialSelectionRect; enum {Type = ResizablePixmapType}; int type() const override; QRectF selectorFrameBounds() const override; void setSelectorFrameBounds(QRectF boundsRect) override; QRectF boundingRect() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; }; #endif // RESIZABLEPIXMAPITEM_H #include "resizablepixmapitem.h" #include <QPen> #include <QGraphicsScene> #include <QPainter> #include "CustomGraphicsScene.h" #include <QJsonDocument> #include <QJsonObject> #include <QJsonArray> ResizablePixmapItem::ResizablePixmapItem(QPixmap pixmap) : mPixmap(pixmap)//, ImageFilePath(path) { setOwnerItem(this); //Fügt die Standart Image File Pfade hinzu DefaultImagePaths << "://resource/quick.png"; setImageFilePath(DefaultImagePaths.first()); } int ResizablePixmapItem::type() const { return Type; } QRectF ResizablePixmapItem::selectorFrameBounds() const { return rect(); } void ResizablePixmapItem::setSelectorFrameBounds(QRectF boundsRect) { prepareGeometryChange(); setRect(boundsRect); update(); } QRectF ResizablePixmapItem::boundingRect() const { return selectorFrameBounds(); }
Than here the resizablehandlerect:
#ifndef RESIZABLEHANDLERECT_H #define RESIZABLEHANDLERECT_H #include <QRectF> #include <QPainter> #include <QGraphicsItem> #include "handleitem.h" class ResizableHandleRect { public: ResizableHandleRect(); virtual ~ ResizableHandleRect(); virtual QRectF selectorFrameBounds() const = 0; virtual void setSelectorFrameBounds(QRectF boundsRect) = 0; void drawHandlesIfNecessary(bool ShouldDrawHandles); QPixmap getPixmap() const; void setPixmap(const QPixmap &value); void setOwnerItem(QGraphicsItem *value); private: void drawHandles(); QRectF topLeftHandleRect; QRectF topRightHandleRect; QRectF bottomRightHandleRect; QRectF bottomLeftHandleRect; QRectF topCenterHandleRect; QRectF bottomCenterHandleRect; QRectF rightCenterHandleRect; QRectF leftCenterHandleRect; QList<HandleItem * > handleList; bool handlesAddedToScene = false; QGraphicsItem * ownerItem; }; #endif // RESIZABLEHANDLERECT_H #include "resizablehandlerect.h" #include <QGraphicsScene> #include <QDebug> #include <QCursor> ResizableHandleRect::ResizableHandleRect() { } ResizableHandleRect::~ResizableHandleRect() { } void ResizableHandleRect::drawHandles() { qDebug() << "ResizableHandleRect DrawHandles triggered!"; // Erstellen und Hinzufügen der Handles zur Szene //Populate handles in list if(handleList.count() == 0){ handleList.append(new HandleItem(HandleItem::TopLeft)); handleList.append(new HandleItem(HandleItem::TopCenter)); handleList.append(new HandleItem(HandleItem::TopRight)); handleList.append(new HandleItem(HandleItem::RightCenter)); handleList.append(new HandleItem(HandleItem::BottomRight)); handleList.append(new HandleItem(HandleItem::BottomCenter)); handleList.append(new HandleItem(HandleItem::BottomLeft)); handleList.append(new HandleItem(HandleItem::LeftCenter)); } //Set up pen QPen mPen; mPen.setWidth(2); mPen.setColor(Qt::black); //Top left handle QPointF topLeftCorner = selectorFrameBounds().topLeft() + QPointF(-8.0,-8.0); topLeftHandleRect = QRectF(topLeftCorner,QSize(8,8)); handleList[0]->setRect(topLeftHandleRect); if(!handleList.isEmpty() && (!handlesAddedToScene)){ handleList[0]->setPen(mPen); //handleList[0]->setBrush(QBrush(Qt::black)); ownerItem->scene()->addItem(handleList[0]); handleList[0]->setParentItem(ownerItem); handleList[0]->setCursor(Qt::SizeFDiagCursor); } //Top Center QPointF topCenterCorner = QPointF(selectorFrameBounds().left() + selectorFrameBounds().width() / 2.0 - 4.0, selectorFrameBounds().top()-4.0); topCenterHandleRect = QRectF(topCenterCorner,QSize(8,8)); handleList[1]->setRect(topCenterHandleRect); if(!handleList.isEmpty() && (!handlesAddedToScene)){ handleList[1]->setPen(mPen); //handleList[1]->setBrush(QBrush(Qt::gray)); ownerItem->scene()->addItem(handleList[1]); handleList[1]->setParentItem(ownerItem); handleList[1]->setCursor(Qt::SizeVerCursor); } //Top right QPointF topRightCorner = selectorFrameBounds().topRight() + QPointF(0,-8.0); topRightHandleRect = QRectF(topRightCorner,QSize(8,8)); handleList[2]->setRect(topRightHandleRect); if(!handleList.isEmpty() && (!handlesAddedToScene)){ handleList[2]->setPen(mPen); //handleList[1]->setBrush(QBrush(Qt::gray)); ownerItem->scene()->addItem(handleList[2]); handleList[2]->setParentItem(ownerItem); handleList[2]->setCursor(Qt::SizeBDiagCursor); } //Right Center QPointF rightCenterCorner = QPointF(selectorFrameBounds().right() - 4.0, selectorFrameBounds().top() + selectorFrameBounds().height() / 2.0 - 4.0); rightCenterHandleRect = QRectF(rightCenterCorner, QSize(8, 8)); handleList[3]->setRect(rightCenterHandleRect); if (!handleList.isEmpty() && (!handlesAddedToScene)) { handleList[3]->setPen(mPen); ownerItem->scene()->addItem(handleList[3]); handleList[3]->setParentItem(ownerItem); handleList[3]->setCursor(Qt::SizeHorCursor); } //Bottom right QPointF bottomRightCorner = selectorFrameBounds().bottomRight() + QPointF(0,0); bottomRightHandleRect = QRectF(bottomRightCorner,QSize(8,8)); handleList[4]->setRect(bottomRightHandleRect); if(!handleList.isEmpty() && (!handlesAddedToScene)){ handleList[4]->setPen(mPen); //handleList[2]->setBrush(QBrush(Qt::gray)); ownerItem->scene()->addItem(handleList[4]); handleList[4]->setParentItem(ownerItem); handleList[4]->setCursor(Qt::SizeFDiagCursor); } // Bottom Center QPointF bottomCenterCorner = QPointF(selectorFrameBounds().left() + selectorFrameBounds().width() / 2.0 - 4.0, selectorFrameBounds().bottom()-4.0); bottomCenterHandleRect = QRectF(bottomCenterCorner, QSize(8, 8)); handleList[5]->setRect(bottomCenterHandleRect); if (!handleList.isEmpty() && (!handlesAddedToScene)) { handleList[5]->setPen(mPen); ownerItem->scene()->addItem(handleList[5]); handleList[5]->setParentItem(ownerItem); handleList[5]->setCursor(Qt::SizeVerCursor); } //Bottom left QPointF bottomLeftCorner = selectorFrameBounds().bottomLeft() + QPointF(-8,0); bottomLeftHandleRect = QRectF(bottomLeftCorner,QSize(8,8)); handleList[6]->setRect(bottomLeftHandleRect); if(!handleList.isEmpty() && (!handlesAddedToScene)){ handleList[6]->setPen(mPen); //handleList[3]->setBrush(QBrush(Qt::gray)); ownerItem->scene()->addItem(handleList[6]); handleList[6]->setParentItem(ownerItem); handleList[6]->setCursor(Qt::SizeBDiagCursor); } // Left Center QPointF leftCenterCorner = QPointF(selectorFrameBounds().left() - 4.0, selectorFrameBounds().top() + selectorFrameBounds().height() / 2.0 - 4.0); leftCenterHandleRect = QRectF(leftCenterCorner, QSize(8, 8)); handleList[7]->setRect(leftCenterHandleRect); if (!handleList.isEmpty() && (!handlesAddedToScene)) { handleList[7]->setPen(mPen); ownerItem->scene()->addItem(handleList[7]); handleList[7]->setParentItem(ownerItem); handleList[7]->setCursor(Qt::SizeHorCursor); } handlesAddedToScene = true; } void ResizableHandleRect::setOwnerItem(QGraphicsItem *value) { ownerItem = value; } void ResizableHandleRect::drawHandlesIfNecessary(bool ShouldDrawHandles) { qDebug() << "DrawHandles" << ShouldDrawHandles << ownerItem->isSelected(); if(!ownerItem){ qWarning() << "ResizableHandleRect : No ownerItem set. Not drawing any\ handle. Please call setOwnerItem on your ResizableHandleRect subclass"; return; } if(ownerItem->isSelected() && ShouldDrawHandles == true){ drawHandles(); handlesAddedToScene = true; }else if(!ownerItem->isSelected() | (ShouldDrawHandles == false)){ //Remove the handles foreach (HandleItem * handleItem, handleList) { ownerItem->scene()->removeItem(handleItem); } qDeleteAll(handleList); handleList.clear(); handlesAddedToScene = false; } }
and the handleitem:
#include "handleitem.h" #include "resizablehandlerect.h" #include <QGraphicsSceneMouseEvent> #include <QDebug> HandleItem::HandleItem(Position position) : handlePosition(position) { setFlag(QGraphicsItem::ItemIsMovable); } void HandleItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { ResizableHandleRect *rectItem = dynamic_cast<ResizableHandleRect *>(parentItem()); if (!rectItem) { return; // Wenn das Parent-Item kein ResizableHandleRect ist, beende die Funktion } QRectF boundingFrameRect = rectItem->selectorFrameBounds(); switch (handlePosition) { case TopLeft: qDebug() << "Case TOPLeft:" << event->pos(); boundingFrameRect.setTopLeft(event->pos() + QPointF(6, 6)); break; case TopCenter: qDebug() << "Case TOP_Center:" << event->pos() + QPointF(+6,0) << "SelectoFrameBounds: "<< boundingFrameRect; boundingFrameRect.setTop(event->pos().y() + 6); break; case TopRight: qDebug() << "Case TOPRight:" << event->pos(); boundingFrameRect.setTopRight(event->pos() + QPointF(-6, 6)); break; case RightCenter: qDebug() << "Case RightCenter:" << event->pos(); boundingFrameRect.setRight(event->pos().x() - 6); break; case BottomRight: qDebug() << "Case BOTTOMRight:" << event->pos(); boundingFrameRect.setBottomRight(event->pos() + QPointF(-6, -6)); break; case BottomCenter: qDebug() << "Case BottomCenter:" << event->pos(); boundingFrameRect.setBottom(event->pos().y() - 6); break; case BottomLeft: qDebug() << "Case BOTTOMLeft:" << event->pos(); boundingFrameRect.setBottomLeft(event->pos() + QPointF(6, -6)); break; case LeftCenter: qDebug() << "Case LeftCenter:" << event->pos(); boundingFrameRect.setLeft(event->pos().x() + 6); break; default: break; } rectItem->setSelectorFrameBounds(boundingFrameRect.normalized()); }
-
@StudentScripter said in How to resize a qgraphicsitemgroup? (Drag and drop) HELP needed:
(haven't found a way to make this work for the graphicsitemgroup, anyone got an idea?)
Yes: the idea (I suggest) is that you cannot do this.
QGraphicsItemRect
QGraphicsItemGroup
does not have its own rectangle, as it says its purpose is to calculate a bunding rect from its children. Do you not think that is the implication of the SO post? Anyway, I leave it to you. -
@JonB said in How to resize a qgraphicsitemgroup? (Drag and drop) HELP needed:
QGraphicsItemRect does not have its own rectangle, as it says its purpose is to calculate a bunding rect from its children
QGraphicsRectItem
or the group?! The group is just aQGraphicsItem
with some nice functions to handle the childs. And the group also has apaintEvent
to make look like you wish.@StudentScripter said in How to resize a qgraphicsitemgroup? (Drag and drop) HELP needed:
I know that the boundingrect of qgraphicsitemgroup is determined by the size of its children
Not 100% correct. Since the
QGraphicsItemGroup
is just another item on the scene, it has its ownboundingRect
(which includes all childs, but can go beyond that)You also have
to to limit the item to the minimum size required to include all children. As the documentation states, you can
OR
it withboundingRect()
to get all childs + the own boundings as new rect.After all, in some cases
QGraphicsItemGroup
is not drawn at all and only stays a logical group.Btw: Found this topic here... unfortunately no reply :(
But it can be done.Edit:
In the linked topic the group inherits from
QObject
andQGraphicsItemGroup
and therefore can make use of signals and slots. Maybe this helps. -
@Pl45m4 said in How to resize a qgraphicsitemgroup? (Drag and drop) HELP needed:
QGraphicsItemRect does not have its own rectangle, as it says its purpose is to calculate a bunding rect from its children
QGraphicsRectItem or the group?! The group is just a QGraphicsItem with some nice functions to handle the childs. And the group also has a paintEvent to make look like you wish.
My mistype, corrected. I did mean
QGraphicsItemGroup
, which the OP is trying to get to do resizing/positioning of children/members, per the topic title. -
@Pl45m4 Again thanks for making the effort of responding, but i figured that i must return the childboundingrect, otherwise it crashes and thats also what the documentation states.
#include "resizablegraphicsgroupitem.h" #include "qgraphicssceneevent.h" #include "qpainter.h" #include <QPen> ResizableGraphicsGroupItem::ResizableGraphicsGroupItem() { // Initialisierungen hier, falls benötigt setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable); //setOwnerItem(this); } QRectF ResizableGraphicsGroupItem::boundingRect() const { qDebug() << "childRect" << childrenBoundingRect(); return childrenBoundingRect(); } void ResizableGraphicsGroupItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { qDebug() << "Test"; Q_UNUSED(option); Q_UNUSED(widget); painter->save(); //Malt eine Linie um das Rechteck painter->setPen(QPen(Qt::green)); painter->drawRect(boundingRect()); // DIESE GRIFFE MÖCHTE ICH IN DER ANDEREN CPP zeichen @CHAT GPT QRectF rect = boundingRect(); qreal dx = 8; // Breite des Griffs qreal dy = 8; // Höhe des Griffs qreal offset = 8; // Versatz des Griffs painter->drawRect(rect.left() - offset, rect.top() - offset, dx, dy); // Oben links painter->drawRect(rect.right() + offset - dx, rect.top() - offset, dx, dy); // Oben rechts painter->drawRect(rect.left() - offset, rect.bottom() + offset - dy, dx, dy); // Unten links painter->drawRect(rect.right() + offset - dx, rect.bottom() + offset - dy, dx, dy); // Unten rechts // Zeichnet Griffe in der Mitte jeder Seite, die zur Hälfte eingerückt sind painter->drawRect(rect.left() + rect.width() / 2 - dx / 2, rect.top() - offset / 2, dx, dy); // Oben Mitte painter->drawRect(rect.right() + offset / 2 - dx, rect.top() + rect.height() / 2 - dy / 2, dx, dy); // Rechts Mitte painter->drawRect(rect.left() + rect.width() / 2 - dx / 2, rect.bottom() + offset / 2 - dy, dx, dy); // Unten Mitte painter->drawRect(rect.left() - offset / 2, rect.top() + rect.height() / 2 - dy / 2, dx, dy); // Links Mitte //drawHandlesIfNecessary(); painter->restore(); }
My goal is to have a way of grouping all graphicsitems so i can apply resizing and moving transforms to all items at once using dragging, like i do with my independent graphicsitems already.
-
@StudentScripter said in How to resize a qgraphicsitemgroup? (Drag and drop) HELP needed:
i figured that i must return the childboundingrect, otherwise it crashes and thats also what the documentation states.
I was talking about the painted (visible area) of your
QGraphicsItemGroup
... what the boundings of your painted (group) area are, not the actual size (bounding) of the group and how you would reimplementboundingRect()
.
By default the group includes all children, but if you add something onto it and actually want to paint your "group", you canOR
the default child- and the groups own bounding rect, to get a rect that includes everything properly. -
@Pl45m4 I tried another thing now. Just using the group as way of organizing but setting a qgraphicsrectitem as parent of the qgraphicsitem group. On mouse release i position the qgraphicsrectitem above the groupitem:
if(DragSelectionInProgress == true){ qDebug() << "SelectionInProgress" << GroupSelectionRect; //Erstelle eine Liste aller selecteten items die nicht das grouprect sind und füge alle items dieser Liste dem grouprect hinzu if(GroupSelectionRect){ QList<QGraphicsItem *> selectedItems = this->selectedItems(); QList<QGraphicsItem *> itemsToAdd; foreach(QGraphicsItem *item, selectedItems) { if(item != GroupSelectionRect && item != SelectionRectPixItem) { itemsToAdd.append(item); } } if(itemsToAdd.count() > 1){ foreach(QGraphicsItem *item, itemsToAdd) { // Check if the item is a pixmap item or a rect item ResizablePixmapItem *rectItem = qgraphicsitem_cast<ResizablePixmapItem *>(item); if(rectItem){ rectItem->setShouldDrawHandles(false); rectItem->drawHandlesIfNecessary(false); //rectItem->setParentItem(SelectionRectPixItem); } GroupSelectionRect->addToGroup(item); } GroupSelectionRect->setParentItem(SelectionRectPixItem); SelectionRectPixItem->setRect(GroupSelectionRect->boundingRect()); //GroupSelectionRect->setSelected(true); } } DragSelectionInProgress = false; }else{ } QGraphicsScene::mouseReleaseEvent(event); }
I can calculate exactly how many pixel the qgraphicsrectitem is resized, but how do i apply this to the group? I want the graphicsitemgroup to mimic the proportions of the qgraphicsrectitem. It should only resize, but stay anchored in the corner that is not moved.
The green outline below is the groupitem, the handles are from the qgraphicsrectitem laying above: