1

Currently, I'm joining two QGraphicsPixmapItem with a line and able to move them around, but when when I add a third QGraphicsPixmapItem and try to connect it to one of them, it breaks the previous joined line.

Here is my current code :



#include <QApplication>

#include <QGraphicsScene>

#include <QGraphicsView>

#include <QGraphicsPixmapItem>

#include <QGraphicsLineItem>

#include <QPixmap>

class CustomElipse : public QGraphicsPixmapItem

{

public:

    CustomElipse (const QPixmap& pixmap) : QGraphicsPixmapItem(pixmap) {

        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) {

        int xOffset = pixmap().rect().x() + pixmap().width()/2;

        int yOffset = pixmap().rect().y() + pixmap().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(QPixmap(":green.png"));

    scene.addItem(elipse1);

    CustomElipse *elipse2 = new CustomElipse(QPixmap(":green.png"));

    scene.addItem(elipse2);

 CustomElipse *elipse3 = new CustomElipse(QPixmap(":green.png"));

    scene.addItem(elipse3);

    QGraphicsLineItem *line = scene.addLine(QLineF(40, 40, 80, 80));

    elipse1->addLine(line, true);

    elipse2->addLine(line, false);

    elipse3->addLine(line,false);

    QGraphicsView view(&scene);

    view.show();

    return a.exec();

}



I tried creating a new line and connecting it like the previous one. I know it overrides the previous line but saving it is also not a good idea because one item might point to 100 others.

QGraphicsLineItem *line1 = scene.addLine(QLineF(40, 40, 80, 80));
elipse3->addLine(line,true);
elipse2->addLine(line,false);
Toloka
  • 23
  • 5

1 Answers1

0

Your CustomElipse can only have one line attached to it at a time, hence why adding a second line will detach it from any other line attached to it.

What you need is to consider allowing your item to handle being attached to more than one line, so instead of QGraphicsLineItem *line;, you could use a list of lines. Same thing goes for bool isP1;.

That leads to your code needing a necessary change for moving the line to its center method, so it handles all lines attached to it, which requires a simple loop that goes through the list of lines.

class CustomElipse : public QGraphicsPixmapItem
{
public:
    CustomElipse (const QPixmap& pixmap) : QGraphicsPixmapItem(pixmap)
    {
        setFlag(QGraphicsItem::ItemIsMovable);
        setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
    }

    void addLine(QGraphicsLineItem *line, bool isPoint1)
    {
        //instead of replacing the line
        //make it append it to the previous ones
        this->line->append(line);

        //append the bool that matches the line appended
        isP1.append(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)
    {
        int xOffset = pixmap().rect().x() + pixmap().width()/2;
        int yOffset = pixmap().rect().y() + pixmap().height()/2;
        QPointF newCenterPos = QPointF(newPos.x() + xOffset, newPos.y() + yOffset);

        // Move the required point of the line to the center of the elipse
        //A simple loop to iterate through the list of lines and isP1 bool
        for(int i = 0; i < line->size(); i++)
        {
            QPointF p1 = isP1.at(i) ? newCenterPos : line->at(i)->line().p1();
            QPointF p2 = isP1.at(i) ? line->at(i)->line().p2() : newCenterPos;
            line->at(i)->setLine(QLineF(p1, p2));
        }
    }

private:
    //a list instead of a single line 
    QList<QGraphicsLineItem *> *line = new QList<QGraphicsLineItem *>;
    //same for isP1
    QList<bool> isP1;
};

int main(int argc,char*argv[])
{
    QApplication a(argc, argv);
    
    QGraphicsScene scene;

    CustomElipse *elipse1 = new CustomElipse(QPixmap(":green.png"));
    scene.addItem(elipse1);

    CustomElipse *elipse2 = new CustomElipse(QPixmap(":green.png"));
    scene.addItem(elipse2);

    CustomElipse *elipse3 = new CustomElipse(QPixmap(":green.png"));
    scene.addItem(elipse3);

    CustomElipse *elipse4 = new CustomElipse(QPixmap(":green.png"));
    scene.addItem(elipse4);

    QGraphicsLineItem *line = scene.addLine(QLineF(40, 40, 80, 80));
    QGraphicsLineItem *line1 = scene.addLine(QLineF(80, 80, 120, 120));
    QGraphicsLineItem *line2 = scene.addLine(QLineF(80, 80, 120, 120));
    QGraphicsLineItem *line3 = scene.addLine(QLineF(80, 80, 120, 120));

    //only one item can be the first point of a line
    //so one item uses true, the second must use false
    elipse1->addLine(line, true);
    elipse1->addLine(line1, true);

    elipse2->addLine(line, false);
    elipse2->addLine(line2,false);

    elipse3->addLine(line1,false);
    elipse3->addLine(line2,true);
    elipse3->addLine(line3,true);

    elipse4->addLine(line3,false);

    QGraphicsView view(&scene);

    view.show();

    return a.exec();
}

Here's the result:

enter image description here