QGraphicView图形视图框架
一、核心基础概念
GraphicsView框架采用“场景-图元-视图”三层架构,三者各司其职、协同工作,用通俗比喻可精准理解:
QGraphicsScene(场景):对应“无限大的世界”,是不可见的逻辑容器,负责管理所有图元(添加、删除、碰撞检测),维护绝对坐标系,支持通过setSceneRect()划定视图默认显示范围(非限制场景大小)。 QGraphicsItem(图元):对应“世界中的万物”,是可视化内容的本体(如图片、矩形),需定义自身形状(boundingRect)和绘制逻辑(paint),位置属性由自身坐标系决定,承载具体显示内容。 QGraphicsView(视图):对应“观察世界的眼睛”,是唯一的可视化窗口,负责将场景中的图元绘制到屏幕,提供取景控制(拖拽、缩放)、绘制优化和事件转发,无视图则场景与图元无法显示。
- 核心规则:视图仅改变“观察视角”,不修改场景和图元的真实属性(位置、大小),实现“视图与数据分离”的设计思想。
二、三层坐标体系
场景坐标系(绝对坐标):原点在场景中心,X轴向右为正、Y轴向下为正(新手高频踩坑点),图元真实位置以此为标准,不受视图操作影响。 图元自身坐标系(局部坐标):定义图元内部的位置基准,原点(锚点)由boundingRect()决定,可设为左上角、中心等任意位置,用于控制图元内容的绘制范围。 视图坐标系(屏幕坐标):原点在视图左上角,X轴向右为正、Y轴向下为正,随视图拖拽、缩放变化,仅反映屏幕显示位置,不代表图元真实位置。锚点规则(图元位置核心)
图元的setPos(x,y)始终指向自身坐标系的原点(锚点),锚点位置由图元类型决定:
自定义图元(继承QGraphicsItem):锚点由boundingRect()定义,例如返回QRectF(-w/2, -h/2, w, h)时,锚点为图片中心;返回QRectF(0, 0, w, h)时,锚点为图片左上角。 原生图元(如QGraphicsPixmapItem):默认锚点为左上角,可通过setOffset(-w/2, -h/2)改为中心锚点,无需重写函数。图元的两种实现方式
自定义图元(继承QGraphicsItem)
强制重写两个纯虚函数(否则编译报错):
boundingRect():定义图元显示范围,建议预留2px边距(避免绘制内容被裁剪、锯齿),同时确定锚点位置。 paint():按自身坐标系绘制内容,需与boundingRect()坐标对齐,否则出现错位(如原代码中paint函数y坐标笔误导致图片下移)。优点:灵活性极高,可添加边框、阴影、文字等自定义效果;缺点:需手动编写代码,易出现笔误。
- 详细解释boundingRect()和paint()两个纯虚函数
boundingRect() const Qt 会根据这个函数返回的矩形,做一个「看不见的矩形框」,框外的内容一律剪掉,框内的内容正常显示。
只负责「划地盘,告诉 Qt「我这个图片项,占了多大的矩形区域」
返回类型QRectF(x, y, w, z)在场景中(x, y)的位置裁剪一个宽为w,高为h的矩形区域 paint() 这个函数是 Qt 唯一的「绘图入口」,你想在画布上显示的所有内容(图片、文字、线条、矩形),必须写在这个函数里
只负责「在划定的地盘里画画」,告诉 Qt「在这个区域里,具体要画什么内容、画在哪」
paint()没有权利决定自己能画多大、画在哪一片区域,它的绘制范围完全被boundingRect()限制死了
- 你在
paint()里画的内容,只要在boundingRect()的矩形内 → 正常显示;- 你在
paint()里画的内容,只要超出boundingRect()的矩形 → 直接被裁剪,看不见。✨ 核心铁律:Qt 中所有图形 / 图元,默认的绘制坐标基准点,都是「这个图形的【外切矩形】的左上角」。
参考代码:
#ifndef PIXITEM_H #define PIXITEM_H #include <QGraphicsItem> #include <QPainter> #include <QPixmap> class PixItem : public QGraphicsItem { public: PixItem(QPixmap *pixmap); private: QPixmap pix; public: //返回固定区域 QRectF boundingRect() const; void paint(QPainter *painer, const QStyleOptionGraphicsItem *option, QWidget* widget = nullptr); }; #endif // PIXITEM_H PixItem::PixItem(QPixmap *pixmap) { pix = *pixmap; } QRectF PixItem::boundingRect() const { //裁剪一个从图元项区域(矩形),且周围扩大2个像素点 return QRectF(-2 - pix.width()/2, -2 - pix.height()/2, pix.width() + 4, pix.height()+4); } void PixItem::paint(QPainter *painer, const QStyleOptionGraphicsItem *option, QWidget *widget) { //绘制图元项,并确认图元项位置,确保图元项在裁剪的区域里面 painer->drawPixmap(-pix.width() / 2, -pix.height() / 2, pix); }
原生图元(如QGraphicsPixmapItem)
- Qt官方封装,内部已重写boundingRect()和paint(),开箱即用,无需自定义代码。优点:极简高效、零风险,兼容所有图形功能;缺点:灵活性稍差,额外效果需补充代码实现。
三、QGraphicView详解
核心结论:一个场景里面可以加入多个图元,但一个视图里只能绑定一个场景,值得注意的是一个场景可以绑定多个视图(一个场景(世界)可以被多只眼睛(多个视图)同时观察,每只眼睛可以有不同的视角(缩放比例、显示区域),但看到的是同一个世界里的同一批图元。)
QGraphicsView的核心职责是渲染某一个场景的内容,它的setScene(QGraphicsScene *scene)函数是「覆盖式」的, 多次调用会让视图解绑上一个场景,重新绑定新场景,最终视图只会显示最后一次绑定的场景内容。QGraphicsScene *scene1 = new QGraphicsScene; QGraphicsScene *scene2 = new QGraphicsScene; QGraphicsView *view = new QGraphicsView; view->setScene(scene1); // 视图绑定scene1,显示scene1的内容 view->setScene(scene2); // 视图解绑scene1,改为绑定scene2,最终只显示scene2void solve() { // 1. 1个场景 + 多个图元 QGraphicsScene *scene = new QGraphicsScene(-500, -500, 1000, 1000); QPixmap pix("your_image.jpg"); QGraphicsPixmapItem *pixItem = new QGraphicsPixmapItem(pix); pixItem->setOffset(-pix.width()/2.0, -pix.height()/2.0); pixItem->setPos(0,0); scene->addItem(pixItem); // 2. 视图1:主视图(大窗口,可缩放拖拽) QGraphicsView *mainView = new QGraphicsView(scene); mainView->setRenderHint(QPainter::Antialiasing); mainView->setDragMode(QGraphicsView::ScrollHandDrag); mainView->setGeometry(100, 100, 800, 600); mainView->show(); // 3. 视图2:缩略图(小窗口,固定比例,显示全貌) QGraphicsView *thumbView = new QGraphicsView(scene); thumbView->setRenderHint(QPainter::Antialiasing); thumbView->setFixedSize(200, 150); thumbView->setGeometry(950, 100, 200, 150); thumbView->show(); }
相关API函数
渲染模式相关
// 1. 抗锯齿:让所有图形/图片的边缘平滑无毛刺、无锯齿 view->setRenderHint(QPainter::Antialiasing); // 2. 图片平滑缩放:放大图片时不会出现马赛克,图片缩放后依然清晰【图片图元必加】 view->setRenderHint(QPainter::SmoothPixmapTransform); // 3. 高质量文本渲染:如果场景里有文字图元,文字显示更清晰(可选,推荐加) view->setRenderHint(QPainter::TextAntialiasing);
视图交互模式相关
// 设置视图的拖拽交互模式,参数是枚举值,效果完全不同 void QGraphicsView::setDragMode(DragMode mode); // ✅ 模式1:按住鼠标左键拖拽 → 平移视图【你的需求必用!所有图形软件通用】 view->setDragMode(QGraphicsView::ScrollHandDrag); // ✅ 模式2:鼠标框选 → 选中场景内的多个图元(比如移动多个图元时用) view->setDragMode(QGraphicsView::RubberBandDrag); // 模式3:默认值,无拖拽行为,鼠标点击只会选中单个图元 view->setDragMode(QGraphicsView::NoDrag); // 开启/关闭视图的所有交互(拖拽、缩放、点击选图元等),默认true开启 view->setInteractive(true); // 开启交互 view->setInteractive(false);// 锁定视图,禁止所有操作
视图相关
// 1. 视图缩放【核心中的核心!滚轮缩放/滑块缩放都是用这个】 // sx:水平缩放倍数 sy:垂直缩放倍数;等比例缩放写相同值即可 // 放大:scale(1.1,1.1) 缩小:scale(0.9,0.9) 原始大小:scale(1.0,1.0) view->scale(qreal sx, qreal sy); // 2. 视图旋转(顺时针旋转,单位:角度°) view->rotate(qreal angle); // 3. 视图平移(相对当前位置,x向右为正,y向下为正) view->translate(qreal dx, qreal dy);

浙公网安备 33010602011771号