Search code examples
c++qtqgraphicsitem

How to use itemChange from QGraphicsItem in Qt


I have custom ellipse QGraphicsItem class and custom line class. On scene I have let's say two ellipses and connection made between them by a line. Ellipse has a pointer to this line and is movable. My problem is that I dont know how to use itemChange() from QGraphicsItem. I want to make connection which will be changing with ellipse movement. So I want to use itemChange() method to change line coordinates in a way that it always will be in center of ellipse. I read documentation from QGraphicsItem::itemChange() but I don't know how to use it in my case.


Solution

  • As others have already noted, you need to override (re-implement) the method in your class.

    Below is a fully working example demonstrating this:

    #include "Dialog.h"
    #include <QApplication>
    #include <QGraphicsScene>
    #include <QGraphicsView>
    #include <QGraphicsEllipseItem>
    #include <QGraphicsLineItem>
    
    
    class CustomElipse : public QGraphicsEllipseItem
    {
    public:
        CustomElipse (const QRectF& rect) : QGraphicsEllipseItem(rect) {
            setFlag(QGraphicsItem::ItemIsMovable);
            setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
        }
    
        void addLine(QGraphicsLineItem *line, bool isPoint1) {
            this->line = line;
            isP1 = isPoint1;
        }
    
        QVariant itemChange(GraphicsItemChange change, const QVariant &value)
        {
            if (change == ItemPositionChange && scene()) {
                // value is the new position.
                QPointF newPos = value.toPointF();
    
                moveLineToCenter(newPos);
            }
            return QGraphicsItem::itemChange(change, value);
        }
    
        void moveLineToCenter(QPointF newPos) {
            // Converts the elipse position (top-left)
            // to its center position
            int xOffset = rect().x() + rect().width()/2;
            int yOffset = rect().y() + rect().height()/2;
    
            QPointF newCenterPos = QPointF(newPos.x() + xOffset, newPos.y() + yOffset);
    
            // Move the required point of the line to the center of the elipse
            QPointF p1 = isP1 ? newCenterPos : line->line().p1();
            QPointF p2 = isP1 ? line->line().p2() : newCenterPos;
    
            line->setLine(QLineF(p1, p2));
        }
    
    private:
        QGraphicsLineItem *line;
        bool isP1;
    };
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        QGraphicsScene scene;
    
        CustomElipse *elipse1 = new CustomElipse(QRectF(30, 30, 15, 25));
        scene.addItem(elipse1);
    
        CustomElipse *elipse2 = new CustomElipse(QRectF(70, 70, 25, 15));
        scene.addItem(elipse2);
    
        QGraphicsLineItem *line = scene.addLine(QLineF(40, 40, 80, 80));
    
        elipse1->addLine(line, true);
        elipse2->addLine(line, false);
    
        QGraphicsView view(&scene);
        view.show();
    
        return a.exec();
    }
    

    The code above draws two movable elipses with a line that's drawn between them. The line position adjusts to follow the elipses.

    When running, you get something like this: Preview of elipses and line