QGraphicView图形视图框架

一、核心基础概念

GraphicsView框架采用“场景-图元-视图”三层架构,三者各司其职、协同工作,用通俗比喻可精准理解:
  • QGraphicsScene(场景):对应“无限大的世界”,是不可见的逻辑容器,负责管理所有图元(添加、删除、碰撞检测),维护绝对坐标系,支持通过setSceneRect()划定视图默认显示范围(非限制场景大小)。
  • QGraphicsItem(图元):对应“世界中的万物”,是可视化内容的本体(如图片、矩形),需定义自身形状(boundingRect)和绘制逻辑(paint),位置属性由自身坐标系决定,承载具体显示内容。
  • QGraphicsView(视图):对应“观察世界的眼睛”,是唯一的可视化窗口,负责将场景中的图元绘制到屏幕,提供取景控制(拖拽、缩放)、绘制优化和事件转发,无视图则场景与图元无法显示。
  • 核心规则:视图仅改变“观察视角”,不修改场景和图元的真实属性(位置、大小),实现“视图与数据分离”的设计思想。

二、三层坐标体系

  1. 场景坐标系(绝对坐标)原点在场景中心X轴向右为正、Y轴向下为正(新手高频踩坑点),图元真实位置以此为标准,不受视图操作影响。
  2. 图元自身坐标系(局部坐标):定义图元内部的位置基准,原点(锚点)由boundingRect()决定,可设为左上角、中心等任意位置,用于控制图元内容的绘制范围。
  3. 视图坐标系(屏幕坐标):原点在视图左上角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,最终只显示scene2
void 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);

 

posted @ 2026-01-16 16:56  菜鸡の编程日常  阅读(4)  评论(0)    收藏  举报