Graphics View框架是用来处理大量2D图形对象的,适合需要高效管理和交互的场景,比如绘图软件、地图编辑或者游戏。它和QPainter的区别在于,Graphics View提供了更高级别的对象管理,而QPainter更偏向于直接绘制。
一、核心组件
-
**QGraphicsScene(场景)**
- 作为图形项的容器,管理所有图元的存储、状态及事件传播。
- 支持背景层、图形项层和前景层的分层绘制,可通过
setBackgroundBrush()
和setForegroundBrush()
设置背景/前景。 - 提供碰撞检测、图元查询(如
itemAt()
)及批量渲染(render()
)功能。
-
**QGraphicsView(视图)**
- 用于显示场景内容,支持多视图查看同一场景,提供缩放、旋转、平移等交互操作。
- 可通过继承并重写
mouseMoveEvent()
、mousePressEvent()
等实现自定义交互逻辑(如坐标追踪、点击响应)。
-
**QGraphicsItem(图元)**
- 所有图形元素的基类,支持自定义形状、事件处理(如鼠标拖拽、键盘事件)及坐标变换14。
- 典型应用包括可拖动的十字标记(
CrossMarkItem
)和可调整大小的兴趣区域(ROIRectItem
)。
二、关键特性
-
事件处理
- 图元可直接响应鼠标点击、悬停、拖拽及键盘事件,事件通过场景传播至目标图元。
示例:
通过重写hoverEnterEvent()
和hoverLeaveEvent()
实现图元悬停缩放效果。
重写mousePressEvent()
,keyPressEvent()
等实现交互。 - 使用
QGraphicsSceneContextMenuEvent
处理右键菜单。
- 图元可直接响应鼠标点击、悬停、拖拽及键盘事件,事件通过场景传播至目标图元。
-
性能优化
- 通过设置
QGraphicsItem::ItemIgnoresTransformations
避免不必要的变换计算。
- 通过设置
-
坐标转换:
- 场景坐标 ↔ 视图坐标:
QGraphicsView::mapToScene()
和mapFromScene()
。 - 项间坐标转换:
QGraphicsItem::mapToItem()
和mapFromItem()
。
- 场景坐标 ↔ 视图坐标:
-
动画与效果:
- 动画 : 使用
QPropertyAnimation
或QGraphicsItemAnimation
。 - 特效 : 应用
QGraphicsEffect
(如阴影、模糊)。
- 动画 : 使用
-
碰撞检测:
scene->collidingItems(item)
检测碰撞项。QGraphicsItem::shape()
自定义碰撞形状。
-
性能优化:
- 启用视图缓存:
view.setCacheMode(QGraphicsView::CacheBackground)
。 - 使用
QGraphicsItem::ItemIgnoresTransformations
避免项随视图缩放。
- 启用视图缓存:
三、基本用法
// 创建场景和项
QGraphicsScene scene;
QGraphicsRectItem *rect = scene.addRect(0, 0, 100, 50);
// 创建视图并关联场景
QGraphicsView view(&scene);
view.setRenderHint(QPainter::Antialiasing); // 抗锯齿
view.show();
四、开发建议
- 模块化设计 :将图元、视图逻辑分离,便于维护扩展(如独立实现
CrossMarkItem
和GraphView
类)。 - 交互优化 :使用
QGraphicsView::setDragMode()
启用拖拽模式,提升用户体验。 - 内存管理: 项通常由场景负责删除,手动删除需谨慎。
- 渲染性能 : 避免过多复杂项;考虑使用 OpenGL 加速(
QGraphicsView::setViewport(new QOpenGLWidget)
)。 - 调试工具 :利用
QGraphicsScene::selectedItems()
和焦点管理功能辅助调试复杂交互逻辑。
五、实例代码
1、基础实例:场景与视图初始化
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// 创建场景并设置范围
QGraphicsScene *scene = new QGraphicsScene();
scene->setSceneRect(0, 0, 800, 600); // :ml-citation{ref="1" data="citationList"}
// 添加矩形图元
QGraphicsRectItem *rectItem = new QGraphicsRectItem(100, 100, 200, 150);
rectItem->setBrush(Qt::blue);
scene->addItem(rectItem); // :ml-citation{ref="1,7" data="citationList"}
// 创建视图并绑定场景
QGraphicsView *view = new QGraphicsView(scene);
view->setWindowTitle("Basic Example");
view->show();
return app.exec();
}
2、图元选择与坐标跟踪
实现功能:
- 鼠标移动时实时显示场景坐标
- 图元选中后支持键盘操作(删除、旋转、缩放)
关键代码:
// 继承 QGraphicsView 实现自定义视图
class CustomView : public QGraphicsView {
protected:
void mouseMoveEvent(QMouseEvent *event) override {
QPoint viewPos = event->pos();
QPointF scenePos = mapToScene(viewPos);
emit positionChanged(scenePos); // 发送坐标信号
}
};
// 图元选中后处理键盘事件
void MyItem::keyPressEvent(QKeyEvent *event) {
switch (event->key()) {
case Qt::Key_Delete:
scene()->removeItem(this); // 删除图元
break;
case Qt::Key_Space:
setRotation(rotation() + 90); // 旋转 90°
break;
}
}
3、自定义图元实例
实现功能:
- 十字标记支持鼠标拖拽
- 拖拽时实时更新位置信号
关键代码:
// CrossMarkItem.h
class CrossMarkItem : public QGraphicsItem {
public:
QRectF boundingRect() const override {
return QRectF(-size_/2, -size_/2, size_, size_);
}
void paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget*) override {
painter->drawLine(-size_/2, 0, size_/2, 0); // 水平线
painter->drawLine(0, -size_/2, 0, size_/2); // 垂直线
}
protected:
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override {
if (change == ItemPositionChange)
emit positionChanged(value.toPointF()); // 发送位置变化信号
return QGraphicsItem::itemChange(change, value);
}
};
4、ROI 矩形与动态更新
实现功能:
- 可调整大小的兴趣区域(ROI)
- 实时显示 ROI 的坐标和尺寸
设计要点:
- 继承
QGraphicsRectItem
并添加控制点 - 在边缘点拖拽时更新 ROI 范围
关键代码:
class ROIRectItem : public QGraphicsRectItem {
public:
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override {
QPointF delta = event->pos() - event->lastPos();
setRect(rect().adjusted(delta.x(), delta.y(), delta.x(), delta.y())); // 动态调整矩形
}
};