QGraphicsView使用三步:建scene、塞item、挂view;scene是数据容器需setScene绑定view,item需提前设flag支持交互,坐标需mapToScene转换,性能优化重在缓存、局部更新和合理sceneRect。

直接上手用 QGraphicsView,核心就三步:建 scene、塞 item、挂 view。别想着先搞懂所有概念再写,先让一个矩形动起来,后面的问题自然浮现。
QGraphicsScene 和 QGraphicsView 怎么配对初始化
scene 是数据容器,view 是显示窗口,二者必须绑定才能看到东西。常见错误是只 new 了 scene 没 setScene 到 view,或者反过来 view 创建时没传 scene 指针导致空指针崩溃。
-
QGraphicsScene不显示,也不需要 parent;它只管存对象、算碰撞、维护 z 值 -
QGraphicsView是QWidget子类,可以直接 addWidget 或 setCentralWidget;必须调用setScene()才能生效 - 场景尺寸默认是 (0, 0, 0, 0),加完 item 后记得调用
scene->setSceneRect()或用fitInView()自适应,否则缩放/滚动可能失效
怎么让图形支持拖拽和选中
内置的 QGraphicsRectItem 等默认不响应鼠标事件,必须显式开启 flag。很多新手卡在这一步,点了半天没反应,其实是忘了设属性。
- 拖拽要开
QGraphicsItem::ItemIsMovable - 选中要开
QGraphicsItem::ItemIsSelectable - 如果想让 item 接收鼠标按下/移动事件,还得额外加
QGraphicsItem::ItemSendsGeometryChanges(比如做吸附时需重写itemChange()) - 注意:这些 flag 要在 add 到 scene 前设置,或用
setFlag()动态改;add 之后再设部分 flag 可能不生效
坐标系混乱、鼠标点不准怎么办
Graphics View 有三套坐标系:item、scene、view。最常出错的是把 QMouseEvent::pos() 直接当 scene 坐标用——它其实是 view 的 widget 坐标,必须转换。
- 鼠标点击位置转 scene 坐标:
view->mapToScene(event->pos()) - scene 坐标转 view 坐标:
view->mapFromScene(scenePos) - item 内部 paint 时用的是局部坐标,
boundingRect()必须覆盖整个可交互区域,否则itemAt()找不到 - 缩放后
mapToScene依然可靠,但别用QGraphicsView::viewport()->rect()当作 scene 尺寸来算比例
性能掉得厉害,几百个 item 就卡顿
不是 item 多就一定慢,而是没启用空间索引或频繁触发全量重绘。Qt 默认用 BSP 树加速查找,但前提是 scene 尺寸合理、item 分布不极端。
- 避免在
paint()里反复 new QPixmap / QFont / QPen;提取为成员变量复用 - 开启缓存:
item->setCacheMode(QGraphicsItem::DeviceCoordinateCache)对静态内容有效 - 关闭抗锯齿(如果不需要):
view->setRenderHint(QPainter::Antialiasing, false) - 慎用
QGraphicsScene::update()全局刷新;优先用item->update()局部更新 - sceneRect 过大(比如设成
QRectF(-1e6,-1e6,2e6,2e6))会拖慢 BSP 构建,按实际内容范围设
真正难的不是写第一版,而是当节点数从 50 跑到 2000、连线从直线变成贝塞尔曲线、还要加实时吸附和网格对齐时,那些隐含在 boundingRect 精度、itemChange 返回值、scene->collidingItems() 调用时机里的细节。这些地方不报错,但一动就偏移、一缩就卡死、一连就漏判——得靠真画布上跑起来才看得见。











