如何在Qt中使用QGraphicsItem的itemChange函数

4

我有自定义的椭圆QGraphicsItem类和自定义的线条类。在场景上,我有两个椭圆,并且由一条线连接它们。椭圆具有指向此线的指针并且可移动。我的问题是,我不知道如何使用QGraphicsItemitemChange()方法。我想创建一个连接,该连接将随着椭圆的移动而改变。因此,我想使用itemChange()方法以一种使线条坐标始终位于椭圆中心的方式来更改线条坐标。我阅读了QGraphicsItem::itemChange()文档,但我不知道如何在我的情况下使用它。


你发布的链接中的示例应该会有所帮助。 - Thalia
但是我不知道如何在对象上使用它? - Makumba
1
在你的类中重写itemChange方法... - Mailerdaimon
2个回答

13

正如其他人已经指出的那样,您需要在您的类中覆盖(重新实现)该方法。

下面是一个完全可行的示例,演示了这一点:

#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();
}

上面的代码绘制了两个可移动的椭圆,并在它们之间绘制了一条线。线的位置会随着椭圆的移动而调整。

运行时,你会得到像这样的东西:

elipses和line的预览

4

对于任何想要Python代码的人,这是@AntonyG代码的翻译:

import sys
from PyQt5 import QtWidgets, QtCore


class CustomItem(QtWidgets.QGraphicsEllipseItem):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.setFlag(self.ItemIsMovable)
        self.setFlag(self.ItemSendsGeometryChanges)
        self.line = None
        self.isPoint = None

    def addLine(self, line, ispoint):
        self.line = line
        self.isPoint = ispoint

    def itemChange(self, change , value):

        if change == self.ItemPositionChange and self.scene():
            newPos = value

            self.moveLineToCenter(newPos)

        return super(CustomItem, self).itemChange(change, value)

    def moveLineToCenter(self, newPos):
        xOffset = self.rect().x() + self.rect().width()/2
        yOffset = self.rect().y() + self.rect().height()/2

        newCenterPos = QtCore.QPointF(newPos.x()+xOffset, newPos.y()+yOffset)

        p1 = newCenterPos if self.isPoint else self.line.line().p1()
        p2 = self.line.line().p2() if self.isPoint else newCenterPos

        self.line.setLine(QtCore.QLineF(p1, p2))


def main():
    app =QtWidgets.QApplication(sys.argv)
    scene = QtWidgets.QGraphicsScene()

    ellipse = CustomItem(QtCore.QRectF(30, 30, 15, 25))
    scene.addItem(ellipse)

    ellipse2 = CustomItem(QtCore.QRectF(70, 70, 25, 15))
    scene.addItem(ellipse2)

    line = scene.addLine(QtCore.QLineF(40, 40, 80, 80))

    ellipse.addLine(line, True)
    ellipse2.addLine(line, False)

    view = QtWidgets.QGraphicsView(scene)
    view.show()

    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

如果有人想要使用鼠标连接两个图形项,请查看这里 - JacksonPro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接