当前位置: 首页 > news >正文

Qt Graphics View框架概述

Qt 的 Graphics View 框架由三类核心对象构成:场景(QGraphicsScene)、视图(QGraphicsView)和图形项(QGraphicsItem)。场景是一个不可见的二维绘图平面,用于管理大量图形项并负责事件分发和状态维护;视图是一个滚动窗口,用于可视化场景内容并处理输入事件;图形项是可绘制的几何元素,可响应鼠标/键盘等交互。在图形视图框架中,场景使用 BSP(二叉空间分区)树等索引算法来快速查找项,支持数百万级别的项查询;视图可关联一个或多个视口来观察同一场景(一个场景可设置多个视图实例)。

1. 基础入门与使用示例

1.1 设置 QGraphicsScene 和 QGraphicsView
使用 Graphics View 框架时,首先创建一个场景并向其中添加图形项,然后创建一个视图来显示该场景。例如:

QGraphicsScene scene;
scene.addText("Hello, world!");
QGraphicsView view(&scene);
view.show();

上述代码通过 scene.addText() 向场景中添加了一个文本项,随后构造了一个与场景关联的 QGraphicsView 并显示视图,注意 QGraphicsScene 本身不可见,它只管理项;要可视化场景,需要创建 QGraphicsView 小部件来承载场景。也可以调用诸如 scene.addRect(), addEllipse(), addPixmap() 等便利函数添加项,或者先 new 一个 QGraphicsItem 子类对象再调用 scene.addItem()。默认情况下,新添加项的局部坐标中心为 (0,0),且其初始场景位置为 (0,0)。

1.2 添加 QGraphicsItem 并响应交互事件
除了使用内置项类(如 QGraphicsRectItemQGraphicsEllipseItemQGraphicsTextItem 等)外,还可以自定义 QGraphicsItem 子类,并在其中重写 boundingRect()paint() 方法实现项的几何和绘制。在子类构造函数中,可以通过 setFlag() 启用交互特性,例如设置 ItemIsMovable 允许鼠标拖动移动项。示例:

class Node : public QGraphicsItem {
public:Node() {setFlag(ItemIsMovable);                // 允许拖动setFlag(ItemIsSelectable);             // 允许选中setCacheMode(DeviceCoordinateCache);   // 启用缓存加速}QRectF boundingRect() const override { /* 返回项包围矩形 */ }void paint(QPainter *p, const QStyleOptionGraphicsItem*, QWidget*) override {/* 绘制项内容 */}
};

上例中,ItemIsMovable 标志会使项支持被单击并拖动,Qt 的内部机制会在鼠标按下、移动事件中自动更新项的位置。其他常用标志如 ItemIsSelectable(支持框选或点击选择项)、ItemIsFocusable(允许获取键盘焦点)等。还可以通过重写鼠标事件(mousePressEvent(), mouseMoveEvent() 等)来定制交互逻辑。需要注意的是,视图会将鼠标和键盘事件转换为场景事件并传递给场景,再由场景分派给相应的项。例如,如果视图检测到用户点击了某项,框架会调用该项的 mousePressEvent(),由项自行处理移动、选中、更新自身绘制等操作。

1.3 坐标系统和视图控制(缩放、滚动)
Graphics View 使用三种坐标系:项坐标、场景坐标和视图坐标。项的所有几何(比如 boundingRect()、碰撞检测)均在项的局部坐标系中定义;项的位置 pos() 定义在其父坐标系(父项或场景坐标)中。视图坐标系以视图窗口左上角为原点,所有鼠标事件最初以视图坐标传入;可以使用 QGraphicsView::mapToScene()mapFromScene() 在视图坐标和场景坐标之间映射点或矩形。视图本身提供仿射变换支持,通过 scale()rotate() 等函数可以对场景内容进行缩放、旋转。例如,调用 view.scale(2,2) 可将视图放大 2 倍,从而实现缩放效果。在视图中也可调用 centerOn()ensureVisible() 快速滚动到场景中的指定点或区域。默认情况下,QGraphicsView 是一个带滚动条的窗口,当场景尺寸大于视图时会自动显示滚动条。如果要控制可视化区域,可通过 view.setSceneRect() 明确设置场景矩形,QGraphicsView 会相应调整滚动条范围。

2. 框架架构原理

2.1 协作关系(Scene-View-Item)

QGraphicsScene 充当图形项的容器,负责管理所有项的位置、层次和状态,并在需要时向视图报告需要重绘的区域。场景维护项的选择与焦点状态(通过 scene->selectedItems()scene->setFocusItem() 等接口),并在场景内容发生变化时发出 changed() 信号通知视图。QGraphicsView 将场景内容渲染到屏幕上,它可以与同一场景关联多个视口,用于从不同角度或大小观察相同数据。视图接收键鼠事件后会转换坐标并将事件转发给场景。QGraphicsItem 是场景中可见元素的基类,所有图形项都继承自它。框架提供了标准项(矩形、椭圆、文本、图像等),也可自定义项来实现特定形状。每个项都运行在自己的本地坐标系中,通过层叠的父子关系可以实现复杂组合结构。

2.2 事件传递机制与渲染流程

当视图捕获到鼠标或键盘事件时,它首先将事件坐标映射到场景坐标,并将事件发送给场景。QGraphicsSceneevent() 函数再根据事件位置确定应该接收事件的顶层项,并调用该项的相应事件处理函数。例如,鼠标点击会最终调用项的 mousePressEvent(),选中可交互项后场景会更新其选择状态。键盘事件默认送至当前具有焦点的项。场景还支持鼠标悬停、拖放、触摸等事件的传播(需调用 setAcceptHoverEvents(true)setAcceptTouchEvents(true) 才能接收)。

渲染方面,QGraphicsView 在绘制时调用每个可见项的 paint() 方法。绘制顺序先绘制父项再绘制子项,且可以通过 setZValue() 调整同级项的叠放顺序。若项未启用缓存(NoCache),每次重绘都会调用 paint();启用 ItemCoordinateCacheDeviceCoordinateCache 后,项将先渲染到离屏缓存,再重复使用缓存。框架内部使用每个项的边界矩形(boundingRect())进行剔除和重绘区域计算:场景构建索引时以此为依据,视图重绘时剔除不在视区的项,并决定需要重新组合的重绘区域。

3. 性能优化技巧

在大规模场景下,绘制性能可能成为瓶颈。典型策略包括:索引调整缓存优化渲染流程优化

  • 索引策略:默认场景使用 BSP 树来加速项查找,但在项数极多且位置信息不经常查询时,更新 BSP 树的开销很大。可调用 scene->setItemIndexMethod(QGraphicsScene::NoIndex) 禁用索引,以减少更新成本(此时场景会逐项遍历处理)。同时,务必使用 scene->setSceneRect() 设定场景边界,避免框架每次自动计算所有项的总体边界。

  • 缓存模式:对静态或仅平移不变形的项,应启用缓存模式以加快重绘。指出,ItemCoordinateCache 在项的本地坐标系中缓存像素,而 DeviceCoordinateCache 则在设备坐标系缓存。通常,对于只会平移但不旋转/缩放的项,DeviceCoordinateCache 性能最好,且保证最高质量。启用缓存后,当项不发生变换时会直接复用缓存,从而大幅降低 paint() 调用次数。

  • 视图优化:通过合理设置视图的更新模式(setViewportUpdateMode)、渲染提示(setRenderHints),可以减少不必要的重绘。例如,可禁用反锯齿(QPainter::Antialiasing)和其它昂贵的状态来提高速度。若需要极致性能,可考虑使用硬件加速:QGraphicsView 允许设置 OpenGL 视口,调用 view->setViewport(new QGLWidget) 即可让视图在 OpenGL 上下文中绘制。

4. 高级用法

  • 自定义 QGraphicsItem 子类:编写自定义项时,应继承 QGraphicsItem 并实现其纯虚函数 boundingRect()(返回包围矩形)和 paint()(实际绘制)。例如,上述 Node 类通过重写这两个函数定义了项形状和外观。通过在构造函数中调用 setFlag() 设置 ItemIsMovableItemIsSelectable 等标志,可轻松启用拖拽和选择功能。如果需要项自身旋转或缩放,可在代码中调用 item->setRotation(angle)setTransform()QGraphicsItem 自带变换功能)。

  • 嵌套视图与坐标变换:可以为同一场景创建多个视图实例,分别显示场景的不同部分或以不同变换观察场景。坐标变换方面,通过 QGraphicsView::mapToScene()/mapFromScene() 可以在视图坐标与场景坐标间互相转换;通过 QGraphicsItem::mapToScene(), mapToItem() 等函数可以在项与项或项与场景之间映射坐标。这些映射函数便于实现复杂交互:例如,将鼠标事件在视图中定位到场景中对应项,或确定某项在另一个视图中的位置。

  • 动画与状态切换:Qt 提供了动画框架来驱动图形视图动画。在 Qt4 时可使用 QGraphicsItemAnimation 结合 QTimeLine 为项设置路径动画;在 Qt5/6 中,更推荐使用 QPropertyAnimation(或 QVariantAnimation 等)来为项的属性(如 posrotationopacity 等)创建动画。例如,可对一个 QGraphicsObject 子类项的 pos 属性应用 QPropertyAnimation,在一定时间内平滑地改变其位置,或者在点击时触发状态切换动画。这样结合状态标志或属性改变,能够实现丰富的可视效果。

http://www.lryc.cn/news/615537.html

相关文章:

  • SpringBoot日志关系
  • 分治-快排-面试题 17.14.最小k个数-力扣(LeetCode)
  • 【Datawhale AI夏令营】让AI读懂财报PDF(多模态RAG)(Task 2)
  • 【无标题】六边形结构在二维拓扑量子色动力学模型中确实具有独特优势,并构建完整的二维拓扑量子色动力学模型。
  • QToolBar 的 addPermanentWidget() 详解与实战场景
  • Python如何将图片转换为PDF格式
  • [SC]SystemC 常见的编译/语法错误与解法(三)
  • PowerShell 入门系列(五):运行命令与命令剖析详解
  • Effective C++ 条款32:确定你的public继承塑模出 is-a 关系
  • pytorch+tensorboard+可视化CNN
  • ubuntu dpkg命令使用指南
  • 【线性代数】其他
  • 机器翻译实战:使用Gensim训练中英文词向量模型及可视化
  • leetcode-C语言-3479.水果成篮 III
  • 写 SPSS文件系统
  • Linux软件编程:shell
  • 组合期权:垂直价差
  • C++ 中的智能指针
  • 电子电气架构 --- 电气/电子架构迁移已拉开帷幕
  • Oracle数据库重启后打开异常状态的检查步骤
  • 一周学会Matplotlib3 Python 数据可视化-网格 (Grid)
  • [IOMMU]面向芯片/SoC验证工程的IOMMU全景速览
  • C# 通过第三方库INIFileParser管理INI配置文件
  • 智慧园区误报率↓76%:陌讯多模态融合算法实战解析
  • 202506 电子学会青少年等级考试机器人一级理论综合真题
  • 闲鱼智能监控机器人:基于 Playwright 与 AI 的多任务监控分析工具
  • 2025年SEVC SCI2区,基于深度强化学习与模拟退火的多无人机侦察任务规划,深度解析+性能实测
  • Dify 从入门到精通(第 24/100 篇):Dify 的实时数据处理与流式输出
  • 微积分 | 外微分
  • HUAWEI交换机命令基础