Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to keep transformations of child item independent from parenitem?
Forum Updated to NodeBB v4.3 + New Features

How to keep transformations of child item independent from parenitem?

Scheduled Pinned Locked Moved Unsolved General and Desktop
qt c++transformparent & child
15 Posts 7 Posters 1.7k Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    StudentScripter
    wrote on last edited by
    #1

    Hello,

    so i have an item with child items, but when i scale the parent item it don't want the child items to be scaled aswell. Im using QGraphicsScale to do the scaling.

        // Create a scaling transformation
        QGraphicsScale *scaleTransform = new QGraphicsScale();
        scaleTransform->setXScale(1.5);  // Scale by 1.5 on the X-axis
        scaleTransform->setYScale(1.5);  // Scale by 1.5 on the Y-axis
         rectItem->setTransformations({scaleTransform});
    
    
    jsulmJ JonBJ jeremy_kJ 3 Replies Last reply
    0
    • S StudentScripter

      Hello,

      so i have an item with child items, but when i scale the parent item it don't want the child items to be scaled aswell. Im using QGraphicsScale to do the scaling.

          // Create a scaling transformation
          QGraphicsScale *scaleTransform = new QGraphicsScale();
          scaleTransform->setXScale(1.5);  // Scale by 1.5 on the X-axis
          scaleTransform->setYScale(1.5);  // Scale by 1.5 on the Y-axis
           rectItem->setTransformations({scaleTransform});
      
      
      jsulmJ Offline
      jsulmJ Offline
      jsulm
      Lifetime Qt Champion
      wrote on last edited by jsulm
      #2

      @StudentScripter Transformations (including scale) should also apply to children. Show more code (how do you add child items?).
      There is also https://doc.qt.io/qt-6/qgraphicsitem.html#setScale which is easier to use than setTransformations.

      https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      0
      • S StudentScripter

        Hello,

        so i have an item with child items, but when i scale the parent item it don't want the child items to be scaled aswell. Im using QGraphicsScale to do the scaling.

            // Create a scaling transformation
            QGraphicsScale *scaleTransform = new QGraphicsScale();
            scaleTransform->setXScale(1.5);  // Scale by 1.5 on the X-axis
            scaleTransform->setYScale(1.5);  // Scale by 1.5 on the Y-axis
             rectItem->setTransformations({scaleTransform});
        
        
        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by
        #3

        @StudentScripter
        Since I think you cannot help but have parent transformations applied to children I can only guess you would have/might be able to "reverse-scale" each child to maintain their original size?

        1 Reply Last reply
        0
        • S StudentScripter

          Hello,

          so i have an item with child items, but when i scale the parent item it don't want the child items to be scaled aswell. Im using QGraphicsScale to do the scaling.

              // Create a scaling transformation
              QGraphicsScale *scaleTransform = new QGraphicsScale();
              scaleTransform->setXScale(1.5);  // Scale by 1.5 on the X-axis
              scaleTransform->setYScale(1.5);  // Scale by 1.5 on the Y-axis
               rectItem->setTransformations({scaleTransform});
          
          
          jeremy_kJ Offline
          jeremy_kJ Offline
          jeremy_k
          wrote on last edited by
          #4

          @StudentScripter said in How to keep transformations of child item independent from parenitem?:

          so i have an item with child items, but when i scale the parent item it don't want the child items to be scaled aswell.

          Why do these items have a parent-child relationship?

          Asking a question about code? http://eel.is/iso-c++/testcase/

          S 1 Reply Last reply
          0
          • A Offline
            A Offline
            Asperamanca
            wrote on last edited by
            #5

            First check if the parent-child relationship is warranted. If it is, and you still don't want to propagate transformations, you can use the flag QGraphicsItem::ItemIgnoresTransformations

            1 Reply Last reply
            2
            • jeremy_kJ jeremy_k

              @StudentScripter said in How to keep transformations of child item independent from parenitem?:

              so i have an item with child items, but when i scale the parent item it don't want the child items to be scaled aswell.

              Why do these items have a parent-child relationship?

              S Offline
              S Offline
              StudentScripter
              wrote on last edited by
              #6

              @jeremy_k @Asperamanca Well these items are "handles" so when the parent is clicked they shall apear at the corners of the paremt. Aswell as when the parent is moved or transformed they are supposed to stay in the corner an be rotated with the parent, but they shall NOT be scaled with the parent.

              JonBJ J jeremy_kJ 3 Replies Last reply
              0
              • S StudentScripter

                @jeremy_k @Asperamanca Well these items are "handles" so when the parent is clicked they shall apear at the corners of the paremt. Aswell as when the parent is moved or transformed they are supposed to stay in the corner an be rotated with the parent, but they shall NOT be scaled with the parent.

                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on last edited by JonB
                #7

                @StudentScripter said in How to keep transformations of child item independent from parenitem?:

                they are supposed to stay in the corner an be rotated with the parent, but they shall NOT be scaled with the parent.

                The fact that you want some parent transformations but not others presumably rules out blanket use of QGraphicsItem::ItemIgnoresTransformations.

                Not something I have done but, depending on how it all works/whether this is doable, you might have to do something like either (a) allow them to accept parent transformations but then reset their scale or (b) ignore parent transformations but then copy parent transformation matrix, reset its scale element and then apply it? One thing I am not sure about is: when you want to sometimes apply scale (on parent) and sometimes not (on children) does the difference in scaling mean that the coordinate transformations like position are now "wrong" e.g. relative to parent? I can sort of imagine how the handles, rotated and moved per the parent, do not come out quite in the right corner position given that scaling is different?

                There are a couple of hits Googling for qgraphicsitem handles you might like to check to see whether anyone has asked your type of question where they need to deal with transformations.

                S 1 Reply Last reply
                0
                • JonBJ JonB

                  @StudentScripter said in How to keep transformations of child item independent from parenitem?:

                  they are supposed to stay in the corner an be rotated with the parent, but they shall NOT be scaled with the parent.

                  The fact that you want some parent transformations but not others presumably rules out blanket use of QGraphicsItem::ItemIgnoresTransformations.

                  Not something I have done but, depending on how it all works/whether this is doable, you might have to do something like either (a) allow them to accept parent transformations but then reset their scale or (b) ignore parent transformations but then copy parent transformation matrix, reset its scale element and then apply it? One thing I am not sure about is: when you want to sometimes apply scale (on parent) and sometimes not (on children) does the difference in scaling mean that the coordinate transformations like position are now "wrong" e.g. relative to parent? I can sort of imagine how the handles, rotated and moved per the parent, do not come out quite in the right corner position given that scaling is different?

                  There are a couple of hits Googling for qgraphicsitem handles you might like to check to see whether anyone has asked your type of question where they need to deal with transformations.

                  S Offline
                  S Offline
                  StudentScripter
                  wrote on last edited by
                  #8

                  @JonB Well thanks Jon, the ideas you stated could be an option, but i have to test it.

                  Regarding googling in the past six months i've read nearly every post or article on qgraphicsitem and handles or transformation, and figured that all examples i could find won't fit my needs. I've build/ tried to replicate around 15 different variations, they are still rotting in my scrapped folder now. xd Meanwhile teaming up with some insides of my professor i figured out a solution atleast in mathematical terms, but the sizing problem was the one thing i still struggelt with on implementation.

                  Regarding the matrix as said i have to check which approach would be viable. Im also currently trying detaching the handles from being child items directly but positioning them independently on my calculation, but the results aren't as smooth so far than with set parent.

                  KenAppleby 0K 1 Reply Last reply
                  0
                  • S StudentScripter

                    @JonB Well thanks Jon, the ideas you stated could be an option, but i have to test it.

                    Regarding googling in the past six months i've read nearly every post or article on qgraphicsitem and handles or transformation, and figured that all examples i could find won't fit my needs. I've build/ tried to replicate around 15 different variations, they are still rotting in my scrapped folder now. xd Meanwhile teaming up with some insides of my professor i figured out a solution atleast in mathematical terms, but the sizing problem was the one thing i still struggelt with on implementation.

                    Regarding the matrix as said i have to check which approach would be viable. Im also currently trying detaching the handles from being child items directly but positioning them independently on my calculation, but the results aren't as smooth so far than with set parent.

                    KenAppleby 0K Offline
                    KenAppleby 0K Offline
                    KenAppleby 0
                    wrote on last edited by KenAppleby 0
                    #9

                    @StudentScripter said in How to keep transformations of child item independent from parenitem?:

                    Im also currently trying detaching the handles from being child items directly but positioning them independently on my calculation, but the results aren't as smooth so far than with set parent.

                    That's the correct approach IMO. Making the Handle items children of the items they are handles to is clearly the wrong structure. It makes more sense to invert that, and have the Handle item the parent. Or perhaps better, use association rather than aggregation.

                    I have implemented this kind of thing using a HandlesSelection item as parent of the representation item, dealing with item selection and movement, without any rendering issues.

                    S 1 Reply Last reply
                    0
                    • KenAppleby 0K KenAppleby 0

                      @StudentScripter said in How to keep transformations of child item independent from parenitem?:

                      Im also currently trying detaching the handles from being child items directly but positioning them independently on my calculation, but the results aren't as smooth so far than with set parent.

                      That's the correct approach IMO. Making the Handle items children of the items they are handles to is clearly the wrong structure. It makes more sense to invert that, and have the Handle item the parent. Or perhaps better, use association rather than aggregation.

                      I have implemented this kind of thing using a HandlesSelection item as parent of the representation item, dealing with item selection and movement, without any rendering issues.

                      S Offline
                      S Offline
                      StudentScripter
                      wrote on last edited by
                      #10

                      @KenAppleby-0 Sounds great, could you maybe share a snippet of how you implemented it? (Obviously only if it's no problem)
                      Anyway i would like to know how you handle it? With setPos() and than update the scene by scene()->update()?

                      KenAppleby 0K 1 Reply Last reply
                      0
                      • S StudentScripter

                        @KenAppleby-0 Sounds great, could you maybe share a snippet of how you implemented it? (Obviously only if it's no problem)
                        Anyway i would like to know how you handle it? With setPos() and than update the scene by scene()->update()?

                        KenAppleby 0K Offline
                        KenAppleby 0K Offline
                        KenAppleby 0
                        wrote on last edited by
                        #11

                        @StudentScripter

                        I had forgotten the details, but having revisited the code ... I used a contentless graphics item to be the parent of both the selectable item and the object drawing the handles or selection. Here's an outline of the code:

                        // This is the graphics object that paints the visual selection around the item.
                        // It could be a QGraphicsItem subclass. I used a QGraphicsObject because it can be more easily animated.
                        class SelectionGraphicsObject : public QGraphicsObject
                        {
                        public:
                          SelectionGraphicsObject(QGraphicsItem * parent, QGraphicsItem * item); // item is the selectable
                        
                          // paint function uses the item's scene bounding rect and other graphical parameters.
                          void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget =nullptr) override;
                        };
                        
                        // A contentless parent class for both the selectable item and the SelectionGraphicsObject.
                        class SelectableGraphicsItem : public QGraphicsRectItem
                        {
                        public:
                          SelectableGraphicsItem(QGraphicsItem * parent, QGraphicsItem * item, QColor selectionColour, int id);
                        
                          void setSelected(bool selected);
                        
                        protected:
                          QGraphicsItem * mItem{ nullptr }; // the selectable item
                          SelectionGraphicsObject * mSelectionItem{ nullptr }; // the graphics object painting the selection.
                        };
                        
                        SelectableGraphicsItem::SelectableGraphicsItem(QGraphicsItem * parent, QGraphicsItem * item)
                          : QGraphicsRectItem{ parent },
                            mItem{ item }
                        {
                          mItem->setParentItem(this);
                          mSelectionItem = new SelectionGraphicsObject{ this, item, selectionColour };
                          mSelectionItem->setVisible(false);
                          mSelectionItem->setFlag(QGraphicsItem::ItemIgnoresTransformations);
                          setFlag(QGraphicsItem::ItemHasNoContents);
                        }
                        
                        void SelectableGraphicsItem::setSelected(bool selected)
                        {
                          mSelectionItem->setVisible(selected);
                          update();
                        }
                        
                        S 1 Reply Last reply
                        1
                        • KenAppleby 0K KenAppleby 0

                          @StudentScripter

                          I had forgotten the details, but having revisited the code ... I used a contentless graphics item to be the parent of both the selectable item and the object drawing the handles or selection. Here's an outline of the code:

                          // This is the graphics object that paints the visual selection around the item.
                          // It could be a QGraphicsItem subclass. I used a QGraphicsObject because it can be more easily animated.
                          class SelectionGraphicsObject : public QGraphicsObject
                          {
                          public:
                            SelectionGraphicsObject(QGraphicsItem * parent, QGraphicsItem * item); // item is the selectable
                          
                            // paint function uses the item's scene bounding rect and other graphical parameters.
                            void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget =nullptr) override;
                          };
                          
                          // A contentless parent class for both the selectable item and the SelectionGraphicsObject.
                          class SelectableGraphicsItem : public QGraphicsRectItem
                          {
                          public:
                            SelectableGraphicsItem(QGraphicsItem * parent, QGraphicsItem * item, QColor selectionColour, int id);
                          
                            void setSelected(bool selected);
                          
                          protected:
                            QGraphicsItem * mItem{ nullptr }; // the selectable item
                            SelectionGraphicsObject * mSelectionItem{ nullptr }; // the graphics object painting the selection.
                          };
                          
                          SelectableGraphicsItem::SelectableGraphicsItem(QGraphicsItem * parent, QGraphicsItem * item)
                            : QGraphicsRectItem{ parent },
                              mItem{ item }
                          {
                            mItem->setParentItem(this);
                            mSelectionItem = new SelectionGraphicsObject{ this, item, selectionColour };
                            mSelectionItem->setVisible(false);
                            mSelectionItem->setFlag(QGraphicsItem::ItemIgnoresTransformations);
                            setFlag(QGraphicsItem::ItemHasNoContents);
                          }
                          
                          void SelectableGraphicsItem::setSelected(bool selected)
                          {
                            mSelectionItem->setVisible(selected);
                            update();
                          }
                          
                          S Offline
                          S Offline
                          StudentScripter
                          wrote on last edited by
                          #12

                          @KenAppleby-0 First of all thanks, but from the example you provided i still don't get how you size the selection item correctly in case the underlying item was transformed by scaling, rotating ... as it appears to me in this case your selection item would be not fitting to the underneath item cause it ignore all transforms?
                          Am i right? Or wasn't this just not needed in your case?

                          Best regards

                          KenAppleby 0K 1 Reply Last reply
                          0
                          • S StudentScripter

                            @jeremy_k @Asperamanca Well these items are "handles" so when the parent is clicked they shall apear at the corners of the paremt. Aswell as when the parent is moved or transformed they are supposed to stay in the corner an be rotated with the parent, but they shall NOT be scaled with the parent.

                            J Offline
                            J Offline
                            Jeremy Katz at Volexity
                            wrote on last edited by
                            #13
                            This post is deleted!
                            1 Reply Last reply
                            0
                            • S StudentScripter

                              @jeremy_k @Asperamanca Well these items are "handles" so when the parent is clicked they shall apear at the corners of the paremt. Aswell as when the parent is moved or transformed they are supposed to stay in the corner an be rotated with the parent, but they shall NOT be scaled with the parent.

                              jeremy_kJ Offline
                              jeremy_kJ Offline
                              jeremy_k
                              wrote on last edited by jeremy_k
                              #14

                              @StudentScripter said in How to keep transformations of child item independent from parenitem?:

                              @jeremy_k @Asperamanca Well these items are "handles" so when the parent is clicked they shall apear at the corners of the paremt. Aswell as when the parent is moved or transformed they are supposed to stay in the corner an be rotated with the parent, but they shall NOT be scaled with the parent.

                              This sounds like the two items are siblings, with a common parent. Only transformations that should be applied to both are performed on the common parent. Using a QGraphicsItemGroup might save a little code.

                              Asking a question about code? http://eel.is/iso-c++/testcase/

                              1 Reply Last reply
                              0
                              • S StudentScripter

                                @KenAppleby-0 First of all thanks, but from the example you provided i still don't get how you size the selection item correctly in case the underlying item was transformed by scaling, rotating ... as it appears to me in this case your selection item would be not fitting to the underneath item cause it ignore all transforms?
                                Am i right? Or wasn't this just not needed in your case?

                                Best regards

                                KenAppleby 0K Offline
                                KenAppleby 0K Offline
                                KenAppleby 0
                                wrote on last edited by
                                #15

                                @StudentScripter

                                Below is code that I can share. It's a complete example which perhaps does what you need. The void HandlesItem::paint() function is where the graphics transformations are done. It's rather long-winded but it at least shows what's required. It draws a painter path around the model items and deals with scaling and rotation of the model items as well as scaling of the graphics view.

                                I'm sorry there is so much code: it's mostly the test framework. It uses mouse wheel events + modifiers to set the scale and rotation of items and the view.

                                // main.cpp
                                
                                #include <QGraphicsRectItem>
                                #include <QGraphicsRectItem>
                                #include <QRandomGenerator>
                                #include <QPainter>
                                
                                // A graphics path item that paints a selection graphic rectangle around a model item.
                                class HandlesItem : public QGraphicsPathItem
                                {
                                public:
                                    HandlesItem(QGraphicsItem * modelItem, QGraphicsItem * parent =nullptr);
                                
                                    void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget =nullptr) override;
                                
                                    void setViewScale(double scale);
                                
                                protected:
                                    QGraphicsItem * mModelItem{ nullptr };
                                };
                                
                                // A contentless graphics item that acts as a proxy for a model item and manages a HandlesItem for it.
                                // The model item position must be set by setting the Proxy item position.
                                // The model item scale and rotation must be set by the setItemScale() and setItemRotation() functions.
                                // Model items and HandleItems are assumed to transform about their center points.
                                
                                class Proxy : public QGraphicsRectItem
                                {
                                public:
                                    Proxy(QGraphicsItem * modelItem, QGraphicsItem * parent =nullptr);
                                
                                    void setSelected(bool selected);
                                
                                    bool isSelected() const;
                                
                                    void setItemRotation(double angle);
                                
                                    void setItemScale(double scale);
                                
                                    void setViewScale(double scale); // call to set the HandleItem's pen width according to the view scale.
                                
                                protected:
                                    QGraphicsItem * mModelItem{ nullptr };
                                    HandlesItem * mHandlesItem{ nullptr };
                                    bool mSelected{ false };
                                };
                                
                                // --------------------------------------
                                
                                HandlesItem::HandlesItem(QGraphicsItem * modelItem, QGraphicsItem * parent)
                                    : QGraphicsPathItem{ parent },
                                      mModelItem{ modelItem }
                                {
                                    setViewScale(1.0);
                                    setTransformOriginPoint(mModelItem->boundingRect().center());
                                }
                                
                                void HandlesItem::setViewScale(double scale)
                                {
                                    QPen pen{ Qt::yellow };
                                    pen.setWidthF(4.0/scale);
                                    setPen(pen);
                                }
                                
                                void HandlesItem::paint(QPainter * painter, [[ maybe_unused ]] const QStyleOptionGraphicsItem * option, [[ maybe_unused ]] QWidget * widget)
                                {
                                    const double scale{ mModelItem->scale() };
                                    const double margin{ 8.0 / scale };
                                    QRectF r{ mModelItem->boundingRect().adjusted(-margin, -margin, margin, margin) };
                                    const QPointF tl{ r.topLeft() }, tr{ r.topRight() }, br{ r.bottomRight() }, bl{ r.bottomLeft() };
                                    QTransform transform;
                                    transform.translate(r.center().x(), r.center().y());
                                    transform.scale(mModelItem->scale(), mModelItem->scale());
                                    transform.rotate(mModelItem->rotation());
                                    transform.translate(-r.center().x(), -r.center().y());
                                    const QPointF tlt{ transform.map(tl) }, trt{ transform.map(tr) }, brt{ transform.map(br) }, blt{ transform.map(bl) };
                                    QPainterPath path;
                                    path.moveTo(tlt); path.lineTo(trt); path.lineTo(brt); path.lineTo(blt); path.lineTo(tlt);
                                    setPath(path);
                                    QGraphicsPathItem::paint(painter, option, widget);
                                }
                                
                                
                                
                                Proxy::Proxy(QGraphicsItem * modelItem, QGraphicsItem * parent)
                                  : QGraphicsRectItem{ parent },
                                    mModelItem{ modelItem }
                                {
                                    mModelItem->setPos(0, 0); // the model item is positioned by the Proxy.
                                    mModelItem->setParentItem(this);
                                    setFlag(QGraphicsItem::ItemHasNoContents);
                                    mHandlesItem = new HandlesItem{ modelItem, this };
                                    setSelected(false);
                                }
                                
                                void Proxy::setSelected(bool selected)
                                {
                                    mSelected = selected;
                                    mHandlesItem->setVisible(mSelected);
                                    update();
                                }
                                
                                bool Proxy::isSelected() const
                                {
                                    return mSelected;
                                }
                                
                                void Proxy::setItemRotation(double angle)
                                {
                                    if (mModelItem)
                                    {
                                        mModelItem->setTransformOriginPoint(mModelItem->boundingRect().center());
                                        mModelItem->setRotation(mModelItem->rotation() + angle);
                                    }
                                }
                                
                                void Proxy::setItemScale(double scale)
                                {
                                    if (mModelItem)
                                    {
                                        mModelItem->setTransformOriginPoint(mModelItem->boundingRect().center());
                                        mModelItem->setScale(mModelItem->scale() * scale);
                                    }
                                }
                                
                                void Proxy::setViewScale(double scale) {
                                    mHandlesItem->setViewScale(scale);
                                }
                                
                                
                                // The remaining code is a QGraphicsView and QGraphicsScene test framework for the above.
                                
                                #include <QGraphicsView>
                                
                                class GraphicsView : public QGraphicsView
                                {
                                public:
                                    GraphicsView(QWidget * parent);
                                
                                    void initialise(QGraphicsScene& scene);
                                
                                protected:
                                
                                    void mousePressEvent(QMouseEvent * event) override;
                                    void mouseMoveEvent(QMouseEvent * event) override;
                                    void mouseReleaseEvent(QMouseEvent *) override;
                                    void wheelEvent(QWheelEvent *) override;
                                
                                    void setSelection(Proxy * item);
                                
                                    void initialiseScene();
                                
                                    void setViewTransform();
                                
                                    QTransform makeTransform() const;
                                
                                    QList<Proxy *> mItems;
                                    Proxy * mSelectedItem{ nullptr };
                                    Proxy * mDragging{ nullptr };
                                    QPointF mMoveScenePoint;
                                    double mScale{ 1.0 };
                                    double mRotation{ 0.0 };
                                };
                                
                                #include <QMainWindow>
                                #include <QGraphicsScene>
                                #include <QBoxLayout>
                                
                                class HandlesMainWindow : public QMainWindow
                                {
                                public:
                                    HandlesMainWindow(QWidget * parent =nullptr);
                                
                                protected:
                                    QGraphicsScene mScene;
                                };
                                
                                
                                
                                HandlesMainWindow::HandlesMainWindow(QWidget * parent)
                                    : QMainWindow(parent)
                                {
                                    QWidget * centralwidget;
                                    QVBoxLayout * verticalLayout;
                                    GraphicsView * graphicsView;
                                
                                    resize(532, 377);
                                    centralwidget = new QWidget(this);
                                    centralwidget->setObjectName("centralwidget");
                                    verticalLayout = new QVBoxLayout(centralwidget);
                                    verticalLayout->setObjectName("verticalLayout");
                                    graphicsView = new GraphicsView(centralwidget);
                                    graphicsView->setObjectName("graphicsView");
                                
                                    verticalLayout->addWidget(graphicsView);
                                    setCentralWidget(centralwidget);
                                    graphicsView->initialise(mScene);
                                }
                                
                                #include <QMouseEvent>
                                #include <QWheelEvent>
                                
                                
                                namespace {
                                    QRandomGenerator& rng() { static QRandomGenerator sRng; return sRng; }
                                    QColor randomColor() {
                                        return QColor{ rng().bounded(64, 255), rng().bounded(64, 255), rng().bounded(64, 255) };
                                    }
                                    QPointF randomPoint() {
                                        return QPointF{ 1.0*rng().bounded(20, 400), 1.0*rng().bounded(20, 400) };
                                    }
                                    QRectF randomRect() {
                                        return QRectF{ 0.0, 0.0, 1.0*rng().bounded(20, 100), 1.0*rng().bounded(20, 100) };
                                    }
                                }
                                
                                
                                GraphicsView::GraphicsView(QWidget * parent)
                                  : QGraphicsView{ parent } {
                                    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
                                    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
                                    setRenderHint(QPainter::Antialiasing);
                                    setTransformationAnchor(ViewportAnchor::NoAnchor);
                                }
                                
                                void GraphicsView::initialise(QGraphicsScene& scene) {
                                    setScene(&scene);
                                    initialiseScene();
                                }
                                
                                void GraphicsView::mousePressEvent(QMouseEvent * event) {
                                    const QPoint p{ event->pos() };
                                    QGraphicsItem * item{ itemAt(p) };
                                    if (item) {
                                        mDragging = qgraphicsitem_cast<Proxy *>(item->parentItem());
                                        mMoveScenePoint = mapToScene(p);
                                    } else {
                                        mDragging = nullptr;
                                    }
                                }
                                
                                void GraphicsView::mouseMoveEvent(QMouseEvent * event) {
                                    const QPoint p{ event->pos() };
                                    if (mDragging) {
                                        const QPointF sp{ mapToScene(p) };
                                        mDragging->moveBy(sp.x() - mMoveScenePoint.x(), sp.y() - mMoveScenePoint.y());
                                        mMoveScenePoint = sp;
                                    }
                                }
                                
                                void GraphicsView::mouseReleaseEvent(QMouseEvent * event) {
                                    mDragging = nullptr;
                                    const QPoint p{ event->pos() };
                                    QGraphicsItem * item{ itemAt(p) };
                                    if (item) {
                                        setSelection(qgraphicsitem_cast<Proxy *>(item->parentItem()));
                                    } else {
                                        setSelection(nullptr);
                                    }
                                }
                                
                                void GraphicsView::wheelEvent(QWheelEvent * event) {
                                    if (event->modifiers() == Qt::NoModifier) {
                                        double deltaScale{ 1.0 };
                                        QPoint p = event->angleDelta();
                                        if (p.y() > 0) {
                                            deltaScale = 1.1;
                                        } else if (p.y() < 0) {
                                            deltaScale = 1.0/1.1;
                                        }
                                        event->accept();
                                        if (mSelectedItem) {
                                            mSelectedItem->setItemScale(deltaScale);
                                        } else {
                                            mScale = mScale * deltaScale;
                                            setViewTransform();
                                        }
                                    }
                                    else if (event->modifiers() == Qt::ControlModifier){
                                        QPoint p = event->angleDelta();
                                        double rotation{ 0.0 };
                                        if (p.y() > 0) {
                                            rotation = 2.0;
                                        } else if (p.y() < 0) {
                                            rotation = -2.0;
                                        }
                                        event->accept();
                                        if (mSelectedItem) {
                                            mSelectedItem->setItemRotation(rotation);
                                        } else {
                                            mRotation += rotation;
                                            setViewTransform();
                                        }
                                    }
                                }
                                
                                void GraphicsView::setSelection(Proxy * item) {
                                    mSelectedItem = item;
                                    if (item) {
                                        item->setSelected(true);
                                    }
                                    for (auto i : mItems) {
                                        if (not (i == item)) {
                                            i->setSelected(false);
                                        }
                                    }
                                }
                                
                                void GraphicsView::setViewTransform() {
                                    setTransform(makeTransform());
                                    for (auto i : mItems) {
                                        i->setViewScale(mScale);
                                    }
                                }
                                
                                QTransform GraphicsView::makeTransform() const {
                                    QTransform result;
                                    const QPointF center{ rect().center() };
                                    result.translate(center.x(), center.y());
                                    result.scale(mScale, mScale);
                                    result.rotate(mRotation);
                                    result.translate(-center.x(), -center.y());
                                    return result;
                                }
                                
                                void GraphicsView::initialiseScene() {
                                    scene()->setBackgroundBrush(QBrush{ Qt::cyan });
                                    for (int i = 0; i < 20; i++) {
                                        QGraphicsRectItem * item{ new QGraphicsRectItem(::randomRect()) };
                                        item->setBrush(QBrush{ ::randomColor() });
                                        Proxy * proxy{ new Proxy{ item } };
                                        proxy->setPos(::randomPoint());
                                        scene()->addItem(proxy);
                                        mItems << proxy;
                                    }
                                }
                                
                                #include <QApplication>
                                
                                int main(int argc, char *argv[])
                                {
                                    QApplication a(argc, argv);
                                    HandlesMainWindow w;
                                    w.show();
                                    return a.exec();
                                }
                                
                                1 Reply Last reply
                                1

                                • Login

                                • Login or register to search.
                                • First post
                                  Last post
                                0
                                • Categories
                                • Recent
                                • Tags
                                • Popular
                                • Users
                                • Groups
                                • Search
                                • Get Qt Extensions
                                • Unsolved