You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用QLine连接两个QGraphicsPixmapItem并实现联动拉伸?

实现QGraphicsPixmapItem的动态连线功能

问题说明

已在QGraphicsScene中添加两个QGraphicsPixmapItem,需要用QLineItem连接二者,且移动任意PixmapItem时,连线能自动拉伸保持连接。参考Qt官方Elastic Nodes Example觉得过于复杂,基于示例实现了椭圆的连线功能,但无法直接替换为QGraphicsPixmapItem,核心问题是PixmapItem的位置与中心计算逻辑和椭圆不同。

解决方案代码

#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsPixmapItem>
#include <QGraphicsLineItem>
#include <QPixmap>

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

    void addLine(QGraphicsLineItem *line, bool isPoint1) {
        m_line = line;
        m_isP1 = isPoint1;
    }

    QVariant itemChange(GraphicsItemChange change, const QVariant &value) override {
        if (change == ItemPositionChange && scene()) {
            QPointF newPos = value.toPointF();
            updateLinePosition(newPos);
        }
        return QGraphicsPixmapItem::itemChange(change, value);
    }

private:
    void updateLinePosition(const QPointF& newPos) {
        // 计算Pixmap的中心位置:新位置 + 自身boundingRect的半宽高
        QRectF bounds = boundingRect();
        QPointF newCenter = newPos + QPointF(bounds.width()/2, bounds.height()/2);

        // 更新连线的对应端点
        QLineF currentLine = m_line->line();
        if (m_isP1) {
            currentLine.setP1(newCenter);
        } else {
            currentLine.setP2(newCenter);
        }
        m_line->setLine(currentLine);
    }

    QGraphicsLineItem* m_line = nullptr;
    bool m_isP1 = false;
};

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

    QGraphicsScene scene;
    // 加载示例图片,替换为你自己的图片路径
    QPixmap pix1(":/images/pic1.png");
    QPixmap pix2(":/images/pic2.png");

    CustomPixmap* pixItem1 = new CustomPixmap(pix1);
    pixItem1->setPos(30, 30);
    scene.addItem(pixItem1);

    CustomPixmap* pixItem2 = new CustomPixmap(pix2);
    pixItem2->setPos(200, 200);
    scene.addItem(pixItem2);

    // 初始化连线,初始位置设为两个Pixmap的中心
    QLineF initialLine(pixItem1->pos() + pixItem1->boundingRect().center(),
                       pixItem2->pos() + pixItem2->boundingRect().center());
    QGraphicsLineItem* line = scene.addLine(initialLine);

    pixItem1->addLine(line, true);
    pixItem2->addLine(line, false);

    QGraphicsView view(&scene);
    view.setSceneRect(0, 0, 400, 400);
    view.show();

    return a.exec();
}

关键知识点

  • 获取Pixmap范围:使用boundingRect()获取QGraphicsPixmapItem的边界矩形,替代椭圆的rect()方法,这是适配PixmapItem的核心。
  • 中心计算逻辑:PixmapItem的pos()是其边界矩形的左上角坐标,因此中心位置为pos() + boundingRect().center(),移动时用新位置加上半宽高即可得到新中心。
  • 位置变更监听:必须设置ItemSendsScenePositionChanges标志,这样在item位置即将改变时,itemChange方法会收到ItemPositionChange信号,提前更新连线位置。
  • 连线更新时机:在itemChange中处理位置变更,确保连线和item移动同步,避免视觉延迟。

内容的提问来源于stack exchange,提问作者Toloka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 09:34:57