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

QGraphicsPolygonItem移动后拖拽顶点位置异常问题求助

问题:QT中移动图形后拖拽顶点位置异常

我正在开发一款基于QT的应用,使用QGraphicsPolygonItem。创建了继承自QGraphicsScene的DiagramScene类,先生成DiagramItem(派生自QGraphicsPolygonItem),并在多边形每个顶点添加红色控制点。当前拖拽顶点功能正常,但移动整个图形后,再拖拽顶点时位置表现不符合预期,怀疑问题出在poly_points[selected_corner_number] = mouseEvent->scenePos();这行代码。


相关代码片段

生成DiagramItem并添加控制点的代码

item = new DiagramItem(myItemType, myItemMenu);
item->setBrush(myItemColor);
addItem(item);
item->setPen(QPen(myLineColor, 2));
item->setPolygon(mouseEvent->scenePos());
item->setSelected(true);
emit itemInserted(item);
this->putPointsOnItem(item);

putPointsOnItem函数实现

void DiagramScene::putPointsOnItem(DiagramItem *item) {
    qDebug() << "putPointsOnItem";
    removeControlPoints();
    QPolygonF p = item->polygon();
    poly_points.clear();
    poly_points = p;
    qDebug() << p;
    for (int i = 0; i < p.size(); i++) {
        QPointF point = item->mapToScene(p[i]);
        QGraphicsEllipseItem *ellipse = addEllipse(QRectF(point.x() -5, point.y() -5, 8, 8), QPen(Qt::red, 3), QBrush(QColor("red")));
        ellipse->setFlag(QGraphicsItem::ItemIsMovable);
        ellipse->setZValue(100000000);
        corner_points.append(ellipse);
        real_corners.append(item);
    }
}

mousePressEvent中检测控制点选中逻辑

void DiagramScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) {

    if (mouseEvent->button() != Qt::LeftButton) {
        return;
    }

    this->finded = false;
    for (int i = 0; i < this->corner_points.length(); i++) {
        QGraphicsEllipseItem *item = this->corner_points[i];
        qDebug() << item;
        if (item->contains(mouseEvent->scenePos())) {
            item->setSelected(true);
            const QList<QGraphicsItem *> items = selectedItems();
            if (items.length()>0) {
                DiagramItem *startItem = qgraphicsitem_cast<DiagramItem *>(items.first());
                startItem->setFlag(QGraphicsItem::ItemIsMovable, false);
                selectedItem = startItem;
            }
            this->selected_corner = item;
            this->selected_corner_point = this->poly_points[i];
            selected_corner_number = i;
            finded = true;
            break;
        }
    }
    if (this->finded == true) {
        QGraphicsScene::mousePressEvent(mouseEvent);
        qDebug() << "POLY POINTS FINDED:";
        qDebug() << poly_points;
        return;
    }
}

mouseMoveEvent中拖拽顶点更新逻辑

void DiagramScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) {

    
    QGraphicsScene::mouseMoveEvent(mouseEvent);

    QString coord = QString("%1, %2").arg(mouseEvent->scenePos().x()).arg(mouseEvent->scenePos().y());
    parentMain->setCoordinates(coord);

    if ((mouseEvent->buttons() & Qt::LeftButton)) {

        const QList<QGraphicsItem *> items = selectedItems();
        
        if (finded == true) {
        
            finded = false;

            for (int i = 0; i < corner_points.size(); ++i) {
                if (corner_points.at(i) == selected_corner) {
                    poly_points[selected_corner_number] = mouseEvent->scenePos();
                    finded = true;
                    break;
                }
            }
            if (finded) {
                qDebug() << poly_points;
                selectedItem->setPolygonItem(poly_points);
                return;
            }

问题根源与修复方案

问题根源

DiagramItem的多边形顶点使用的是自身局部坐标,而非场景坐标。当整个图形被移动后,DiagramItem的场景位置发生偏移,此时直接用鼠标的场景坐标赋值给顶点,会导致顶点位置叠加了图形的偏移量,出现错位。

修复步骤

  1. 修正顶点坐标转换逻辑
    在mouseMoveEvent中,将鼠标的场景坐标转换为DiagramItem的局部坐标后,再赋值给poly_points:

    // 替换原有的poly_points赋值行
    QPointF localPos = selectedItem->mapFromScene(mouseEvent->scenePos());
    poly_points[selected_corner_number] = localPos;
    
  2. 同步控制点与图形的位置
    当移动整个DiagramItem时,需要同步更新控制点的位置,避免控制点停留在原场景位置。可以在DiagramItem中重写itemChange事件监听位置变化:

    QVariant DiagramItem::itemChange(GraphicsItemChange change, const QVariant &value)
    {
        if (change == ItemPositionChange && scene()) {
            DiagramScene* diagramScene = qobject_cast<DiagramScene*>(scene());
            if (diagramScene) {
                diagramScene->updateControlPointsForItem(this);
            }
        }
        return QGraphicsPolygonItem::itemChange(change, value);
    }
    

    然后在DiagramScene中实现更新控制点的函数:

    void DiagramScene::updateControlPointsForItem(DiagramItem* item)
    {
        for (int i = 0; i < corner_points.size(); ++i) {
            if (real_corners[i] == item) {
                QPointF localPoint = item->polygon()[i];
                QPointF scenePoint = item->mapToScene(localPoint);
                corner_points[i]->setRect(scenePoint.x() -5, scenePoint.y() -5, 8, 8);
            }
        }
    }
    
  3. 优化顶点数据存储
    当前poly_points是DiagramScene的成员变量,多图形场景下会被覆盖。建议用QMap<DiagramItem*, QPolygonF>存储每个图形的顶点数据,避免切换选中图形时数据混乱。


内容的提问来源于stack exchange,提问作者Andrés Flórez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 21:50:10