首页 QT系列3:QGraphicsScene
文章
取消

QT系列3:QGraphicsScene

用最接地气的比喻来说,整个过程就像你在玩一个“客厅摄像头直播”游戏。 • QGraphicsScene = 你家客厅(一个超级大的、无边界的空间) • QGraphicsItem = 客厅里摆放的各种家具、玩具、挂画、灯……(这些东西才是真正要被看到的“内容”) • QGraphicsView = 你架在客厅里的一个摄像头 + 显示器(它决定观众最终在屏幕上看到什么) 关键一句话:客厅本身是不会出现在电视上的,只有摄像头拍到的画面才会显示。 整个绘制是怎么一步步发生的?(从头到尾的真实流程) 1 某件事触发了“需要重新画画面”
比如: ◦ 窗口第一次显示出来 ◦ 你拖动了视图(像转动摄像头) ◦ 你滚轮缩放了(像变焦镜头) ◦ 你移动了某个家具(某个 Item 位置变了) ◦ 你手动调用了 update() 或 scene->invalidate() 2 摄像头(QGraphicsView)收到“要重画”的信号
它会先问自己:“我现在对着客厅的哪个区域?要拍多大的范围?”
它根据当前的 ◦ 缩放比例 ◦ 平移位置 ◦ 旋转角度
计算出“我现在能看到客厅的哪一块矩形区域”(这个区域用场景坐标表示) 3 摄像头对客厅喊:“给我把这个区域的东西都画出来!” 4 客厅(QGraphicsScene)收到请求,开始按顺序整理和绘画
客厅会分几个大阶段画(从最底层画到最上层): ◦ 先画背景(你设置的纯色、网格、图片背景……) ◦ 然后画所有家具(也就是所有的 QGraphicsItem) ◦ 最后画前景(比如你自己加的水印、调试用的坐标尺……) 5 最关键、最花时间的其实是第二步——画家具 6 客厅怎么知道该画哪些家具、不该画哪些?(很重要!)
它会先看“摄像头要拍的这个矩形区域”,然后快速找一找: “哪些家具哪怕只露一点点在这个区域里?”
(Qt 内部用一种叫 BSP 树的空间索引来快速找,通常比暴力遍历快非常多)
找到这些“可能要画到的家具”之后,客厅会把它们按 z 值从低到高 排好队(z 值大的会盖在 z 值小的上面,就像前景盖背景一样) 7 轮到每个家具自己上场表演了
客厅会一个接一个地把“画笔”交给每个家具,说:
“现在轮到你了,你画你自己吧!”
每个家具(QGraphicsItem)就会执行自己的 paint() 函数:
void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) 8 { 9 painter->setBrush(Qt::blue); 10 painter->drawEllipse(-20, -20, 40, 40); // 画一个圆 11 painter->drawText(0, 0, “我是小球”); 12 } 13 
注意:这时 painter 已经自动处于这个家具自己的坐标系里了,(0,0) 就是这个家具的中心点或你定义的原点,你不用管它在客厅的绝对位置。 14 所有家具都画完后
客厅把这一整张画好的“大图”交给摄像头 15 摄像头(View)把这张图显示到电视屏幕(也就是窗口)上
完成了!观众(用户)就看到画面了。 极简口诀(背下来就抓到核心了) “场景管东西,视图管镜头” • 东西(家具)放在场景(客厅)里 • 镜头(视图)决定拍哪里、怎么拍(放大缩小旋转平移) • 要重画时 → 镜头告诉场景:给我看这个区域 • 场景按顺序(背景 → 家具按 z 排序 → 前景)画 • 每个家具自己负责把自己画出来 • 镜头把画好的画面显示到屏幕 新手最常掉的几个坑(强烈提醒) • 忘记写 boundingRect() → 家具等于隐身,什么都看不到 • boundingRect() 写得太小 → 鼠标点不到、碰撞检测失效 • 在 paint() 里面做超级复杂的计算 → 界面直接卡死 • 改了数据却不调用 update() → 改了也看不见 • 往场景里一股脑塞几万几十万个小 Item → 不优化基本必崩

本文由作者按照 CC BY 4.0 进行授权