Qt+C++实现圆弧随鼠标移动旋转的坐标问题求助
解决Qt GraphicsScene中圆弧子项的坐标定位与旋转问题
看起来你遇到的核心问题是Qt Graphics View框架中的坐标系统层级混淆——你的圆弧m_arc是椭圆m_ellipse的子项,它的位置和变换都是基于父项的局部坐标系,而非全局场景坐标系,这就是为什么直接用场景坐标设置setPos()会出现偏移的原因。
问题根源拆解
- 你设置了
m_arc->setParentItem(m_ellipse);,这意味着m_arc的pos()是相对于m_ellipse的局部坐标(以m_ellipse的rect左上角为原点),但你计算的intersection_point是场景坐标,直接赋值给子项的pos必然导致坐标错位。 - 你绘制的矩形是直接添加到场景的,用场景坐标自然能正常显示,这也侧面验证了坐标系统的层级问题。
- 你之前凑出来的
-85其实是近似值,本质是没有完成从场景坐标到父项局部坐标的转换,再结合圆弧自身rect的偏移计算。
正确的坐标转换与定位步骤
我们可以通过Qt提供的坐标映射方法来精准计算位置,不需要硬凑数值:
1. 将场景坐标转换为父项局部坐标
当你得到场景坐标的交点intersection_point后,先把它转换为m_ellipse的局部坐标:
QPointF parentLocalPos = m_ellipse->mapFromScene(intersection_point);
2. 计算圆弧的正确位置
你的m_arc的rect是(62.0, 62.0, 50.0, 50.0),它的局部中心坐标是(62+25, 62+25) = (87,87)(宽高都是50,半长为25)。要让圆弧的中心对齐到父项的parentLocalPos,圆弧的pos应该是:
m_arc->setPos(parentLocalPos - QPointF(87, 87));
这就替代了你之前硬写的-85,完全基于坐标逻辑计算,不会有误差。
旋转的正确处理
对于旋转,你需要确保变换原点是圆弧自身的局部中心,而不是父项或场景坐标。直接使用圆弧rect的中心作为变换原点即可:
// 设置旋转原点为圆弧自身的局部中心 m_arc->setTransformOriginPoint(m_arc->rect().center()); // 应用旋转角度 m_arc->setRotation(angleBetweenPositions);
整合后的关键代码
结合你的最终修改,整理成更清晰的版本:
void DrawingScene::mousePressEvent(QGraphicsSceneMouseEvent *event){ p1 = event->scenePos(); QPointF ellipse_center = m_ellipse->rect().center(); QLineF lineToCenter(ellipse_center, p1); // 计算角度 double angleBetweenPositions = lineToCenter.angleTo(m_lineToCenter->line()); QLineF horizontalLine(ellipse_center, QPointF(200.0,140.0)); double angleBetweenLines = horizontalLine.angleTo(lineToCenter); // 计算相对于椭圆中心的偏移 double x = 60.0 * cos(angleBetweenLines * M_PI / 180.0); double y = -60.0 * sin(angleBetweenLines * M_PI / 180.0); QPointF newPoint(x,y); QPointF intersection_point = newPoint + ellipse_center; // 坐标转换:场景坐标 -> 椭圆的局部坐标 QPointF parentLocalPos = m_ellipse->mapFromScene(intersection_point); // 设置圆弧位置:让圆弧中心对齐到交点 m_arc->setPos(parentLocalPos - m_arc->rect().center()); // 旋转处理 m_arc->setCurrentRotation(angleBetweenPositions); m_arc->setTransformOriginPoint(m_arc->rect().center()); m_arc->setRotation(m_arc->getCurrentRotation()); m_lineToCenter->setLine(lineToCenter); }
额外提示
- 尽量使用Qt提供的
M_PI代替手动写3.14,精度更高且更规范 - 子项的所有位置、变换操作都要时刻牢记是基于父项坐标系的,遇到错位先检查坐标映射是否正确
- 可以用
mapToScene()/mapFromScene()、mapToParent()/mapFromParent()这些方法在不同坐标系间转换,避免硬编码偏移值
内容的提问来源于stack exchange,提问作者Juliette Marquis
相关产品推荐
相关产品推荐

