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的场景位置发生偏移,此时直接用鼠标的场景坐标赋值给顶点,会导致顶点位置叠加了图形的偏移量,出现错位。
修复步骤
修正顶点坐标转换逻辑
在mouseMoveEvent中,将鼠标的场景坐标转换为DiagramItem的局部坐标后,再赋值给poly_points:// 替换原有的poly_points赋值行 QPointF localPos = selectedItem->mapFromScene(mouseEvent->scenePos()); poly_points[selected_corner_number] = localPos;同步控制点与图形的位置
当移动整个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); } } }优化顶点数据存储
当前poly_points是DiagramScene的成员变量,多图形场景下会被覆盖。建议用QMap<DiagramItem*, QPolygonF>存储每个图形的顶点数据,避免切换选中图形时数据混乱。
内容的提问来源于stack exchange,提问作者Andrés Flórez
相关产品推荐
相关产品推荐

