QGraphicsScene中自定义QGraphicsItem绕中心旋转及QGraphicsView原点设置
咱们一步步解决你的两个问题:让自定义图形项绕自身中心旋转,以及把QGraphicsView的原点设置到左下角。
一、让Grafica_PPU绕自身中心旋转
你的核心问题在于混淆了场景坐标和图形项的局部坐标,以及手动在paint里处理旋转的方式不对。Qt的QGraphicsItem本身提供了transform系统,用它来处理旋转会更可靠简洁。
修改步骤:
重构Grafica_PPU的坐标逻辑
把图形项的位置从boundingRect中剥离,改用QGraphicsItem自带的setPos()方法设置它在场景中的位置,boundingRect只描述图形项自身的局部矩形(从(0,0)开始)。先修改头文件
areagrafica.h,新增存储自身宽高的成员:private: GraphicModuleData infoGrafiche; qreal Alpha; QString Testo; QPen Penna; qreal m_width, m_height; // 存储自身宽高,避免重复读取infoGrafiche然后修改
areagrafica.cpp的构造函数,设置位置、旋转原点和角度:Grafica_PPU::Grafica_PPU(QString ModuleName, GraphicModuleData tmpInfoGrafiche, QPen Pen, qreal tmpAlpha) : infoGrafiche(tmpInfoGrafiche), Penna(Pen), Testo(ModuleName), Alpha(tmpAlpha), m_width(tmpInfoGrafiche.Width), m_height(tmpInfoGrafiche.Height) { // 设置图形项在场景中的位置 setPos(tmpInfoGrafiche.posX, tmpInfoGrafiche.posY); // 把旋转原点设为图形项自身的中心 setTransformOriginPoint(m_width / 2, m_height / 2); // 设置旋转角度 setRotation(tmpAlpha); // 可选:开启可选/可移动,方便调试 setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable); }修正boundingRect()函数
现在boundingRect要返回图形项的局部坐标范围,同时为了避免旋转后图形被裁剪,我们可以返回一个包含旋转后最大范围的矩形:QRectF Grafica_PPU::boundingRect() const { // 计算旋转后的最大边界(用对角线长度确保覆盖所有旋转情况) qreal maxDim = qMax(m_width, m_height); qreal halfMax = maxDim / 2; return QRectF(-halfMax, -halfMax, maxDim, maxDim); // 如果不需要考虑极端旋转裁剪,也可以直接返回原始矩形: // return QRectF(0, 0, m_width, m_height); }简化paint()函数
现在不需要手动处理translate和rotate了,Qt会通过transform自动帮我们转换坐标系,直接在局部坐标系绘制即可:void Grafica_PPU::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { painter->setPen(Penna); painter->setRenderHint(QPainter::Antialiasing); painter->setRenderHint(QPainter::TextAntialiasing); // 绘制自身矩形(局部坐标从0,0开始) QRectF rect(0, 0, m_width, m_height); painter->drawRect(rect); // 绘制中心圆点 painter->drawPoint(rect.center()); // 绘制居中文字 painter->drawText(rect, Qt::AlignCenter, Testo); }
二、把QGraphicsView的原点设置为左下角
默认QGraphicsView的原点在左上角,我们可以通过修改view的变换矩阵来翻转y轴,再调整平移让原点对齐左下角。
修改主窗口代码:
在MainWindow的构造函数中,添加以下代码(假设你的QGraphicsView对象名为Grafico_View):
// 关联场景和视图 Grafico_View->setScene(Grafico_Scena); // 翻转y轴,将坐标系的y轴方向改为向上(默认是向下) Grafico_View->scale(1, -1); // 平移视图,让场景的左下角对齐视图可视区域的左下角 Grafico_View->translate(0, -Grafico_View->viewport()->height());
处理窗口大小变化:
如果窗口resize,视图的视口高度会变化,需要重新调整平移参数。可以在MainWindow中重写resizeEvent:
void MainWindow::resizeEvent(QResizeEvent *event) { QMainWindow::resizeEvent(event); if (Grafico_View) { // 先重置变换,再重新设置 Grafico_View->resetTransform(); Grafico_View->scale(1, -1); Grafico_View->translate(0, -Grafico_View->viewport()->height()); } }
最后调整调用代码
现在构造函数已经处理了旋转,调用时直接传入角度即可:
GraphicModuleData tmp; tmp.posX = 45; tmp.posY = 100; // 注意:视图翻转y轴后,posY的方向会反过来,按需调整数值 tmp.Height = 22; tmp.Width = 54; // 创建两个测试项,一个旋转0度,一个旋转45度(示例) Grafica_PPU *test = new Grafica_PPU("PP55103", tmp, *Grafico_Matita_Nera, 0.0); Grafica_PPU *test2 = new Grafica_PPU("PP55103", tmp, *Grafico_Matita_Nera, 45.0); Grafico_Scena->addItem(test); Grafico_Scena->addItem(test2);
这样修改后,你的自定义图形项就会绕自身中心旋转,QGraphicsView的原点也会落在左下角了。
内容的提问来源于stack exchange,提问作者Pierluigi Rovere

