- 1. Qt 图形视图框架功能详解
- 1.1. QGraphicsScene(场景)
- 1.2. QGraphicsView(视图)
- 1.3. QGraphicsItem(图形项)
- 1.3.1. 关键函数实现
- 1.3.2. 使用自定义图形项
1. Qt 图形视图框架功能详解
在 Qt 中,图形视图框架主要由 QGraphicsScene、QGraphicsView 和 QGraphicsItem 三大核心类构成,具有丰富功能。
1.1. QGraphicsScene(场景)
-
图形项管理
- 作为图形项的容器,负责存储和管理各种
QGraphicsItem及其派生类对象,如图形、文本、图片等。例如,可以将多个矩形、线条等图形项添加到场景中进行统一管理。 - 提供对图形项的增删改查操作,方便动态调整场景中的内容。
- 作为图形项的容器,负责存储和管理各种
-
事件处理
- 是图形视图框架的事件中心,负责处理场景内图形项的各种事件,像鼠标点击、键盘操作、拖拽等事件。例如,当用户在场景中的某个图形项上点击鼠标时,场景会将该事件传递给对应的图形项进行处理。
- 支持自定义事件过滤器,可用于对场景内事件进行统一管理和预处理。
-
高级功能支持
- 支持拖拽操作,可实现图形项在场景内的拖动以及与其他应用间的拖放交互。
- 配合动画框架,可为场景中的图形项创建动画效果,如平移、旋转、缩放等动画。
- 支持与状态机框架结合,可根据不同状态对场景中的图形项进行相应控制。
看一个简单的例子:
新建QWigdet程序,main.cpp如下:
#include "widget.h"#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsRectItem>
#include <QDebug>int main(int argc, char *argv[])
{QApplication app(argc,argv);//新建场景QGraphicsScene scene;//创建矩形图形项QGraphicsRectItem* item =new QGraphicsRectItem(0,0,100,100); //将图形项添加到场景中scene.addItem(item);//输出(50,50)点处的图形项qDebug()<<scene.itemAt(50,50,QTransform());return app.exec();
}
这里先创建了一个场景,然后创建了一个矩形图形项,并且将该图形项添加到了场景中。
然后使用itemAt()函数返回指定坐标处最顶层的图形项,这里返回的就是刚才添加的矩形图形项。
现在可以运行程序,不过因为还没有设置视图,所以不会出现任何图形界面。
这时可以在应用程序输出栏中看到输出项目的信息。

1.2. QGraphicsView(视图)
-
场景显示
- 用于显示
QGraphicsScene场景中的内容,将场景中的图形项以可视化的方式呈现在窗口上。一个场景可以关联多个视图,不同视图可从不同角度或以不同方式显示同一场景。 - 支持视口的滚动,当场景内容超出视口范围时,可通过滚动条查看完整内容。
- 用于显示
-
交互功能
- 提供视图的缩放功能,允许用户通过鼠标滚轮或调用相关接口对视图进行放大缩小操作,方便查看场景中的细节或整体布局。
- 支持视图的平移,用户可通过拖拽视图或调用相应接口实现视图在场景上的移动,聚焦于感兴趣区域。
- 具备可选择的拖拽模式,如无拖拽、手型拖拽和滚动手型拖拽等模式,满足不同交互需求。
我们继续看上面的例子,在主函数中 "return app.exec();"一行代码前继续添加代码:
#include "widget.h"#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QDebug>int main(int argc, char *argv[])
{QApplication app(argc,argv);//新建场景QGraphicsScene scene;//创建矩形图形项QGraphicsRectItem* item =new QGraphicsRectItem(0,0,100,100); //将图形项添加到场景中scene.addItem(item);//输出(50,50)点处的图形项qDebug()<<scene.itemAt(50,50,QTransform());//为场景创建视图QGraphicsView view(&scene); //设置场景的前景色view.setForegroundBrush(QColor(255,255,0,100)); //设置场景的背景色view.setBackgroundBrush(QPixmap("D://logo2.png"));view.resize(400,300);view.show();return app.exec();
}

这里新建了视图部件,并指定了要可视化的场景。然后为该视图设置了场景前景色和背景图片。
一个场景分为3层:图形项层(ItemLayer)、前景层(ForegroundLayer)和背景层(BackgroundLayer)。
场景的绘制总是从背景层开始,然后是图形项层,最后是前景层。
前景层和背景层都可以使用QBrush进行填充,比如使用渐变和贴图等。
这里的前景色设置为半透明的黄色,当然也可以设置为其他的填充。
代码中使用了QGraphicsView类中的函数设置了场景中的背景和前景,其实也可以使用QGraphicsScene中的同名函数来实现,不过它们的效果并不完全一样。如果使用QGraphicsScene对象设置了场景背景或者前景,那么对所有关联了该场景的视图都有效,而QGraphicsView对象设置的场景的背景或者前景只对它本身对应的视图有效。
可以在这里的代码后面再添加如下代码:
//为场景创建视图2QGraphicsView view2(&scene);view2.resize(400,300);view2.show();

这时运行程序会出现两个视图,但是第二个视图中的背景是白色的。
1.3. QGraphicsItem(图形项)
-
基本功能
- 作为所有图形项的基类,定义了图形项的基本接口和属性,如位置、大小、变换(平移、旋转、缩放)、可见性等。
- 支持绘制操作,可通过重写
paint()函数自定义图形项的绘制方式,实现各种复杂形状和效果的图形显示。 - 鼠标按下、移动、释放、双击、悬停、滚轮和右键菜单事件。
- 键盘输入焦点和键盘事件。
- 拖放事件。
- 分组,使用QGraphicsItemGroup通过parent-child关系来实现。
- 碰撞检测。
- 除此之外,图形项还可以存储自定义的数据,可以使用setData()进行数据存储,然后使用data()获取其中的数据。
-
事件处理
- 拥有丰富的事件处理机制,可处理鼠标事件(如按下、释放、双击等)、键盘事件、轮播事件、拖进拖出事件等。例如,在图形项上实现鼠标悬停时改变形状或颜色的效果。
- 提供事件传播机制,事件可在图形项及其父项之间传递,便于实现复杂的交互逻辑。
-
图形项管理
- 支持图形项的分层管理,可通过设置父项来建立图形项之间的层级关系,子项会随父项一起进行变换操作,如平移、旋转等。
- 具备碰撞检测功能,可检测与其他图形项或形状之间的碰撞关系,为实现游戏、绘图等应用中的交互提供基础。
在 Qt 中,除了使用现成的图形项外,还支持自定义图形项以满足特定需求。我们在接着看上面的例子,这次要增加一个类:
- 创建类
在 Qt Creator 中为项目添加新文件,选择 “C++ 类” 模板,命名为 MyItem,基类设为 QGraphicsItem。
- 修改头文件
对 myitem.h 文件进行如下修改(示例代码,需根据实际需求调整):
#ifndef MYITEM_H
#define MYITEM_H
#include <QGraphicsItem>
class MyItem : public QGraphicsItem
{
public:MyItem();QRectF boundingRect() const override;void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
};
#endif // MYITEM_H
- 实现文件修改
在 myitem.cpp 文件中添加头文件 #include <QPainter>,并定义添加的两个函数。
1.3.1. 关键函数实现
- boundingRect() 函数
该函数用于返回要绘制图形项的矩形区域,定义图形项的外部边界矩形。例如:
QRectF MyItem::boundingRect() const
{return QRectF(-10, -10, 20, 20); // 设置边界矩形,可根据实际图形调整
}
所有的绘图操作都必须限制在图形项的边界矩形之中。而且,QGraphicsView 要使用这个矩形来剔除那些不可见的图形项,还要使用它来确定绘制交叉项目时哪些区域需要进行重新构建。另外,QGraphicsItem 的碰撞检测机制也需要使用到这个边界矩形。如果图形绘制了一个轮廓,那么在边界矩形中包含一半画笔的宽度是很重要的,尽管对于抗锯齿绘图并不需要这些补偿。
- paint() 函数
该函数用于执行实际的绘图操作,其原型如下:
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr)
一般会被 QGraphicsView 调用,用来在本地坐标中绘制图形项中的内容。其中,painter 参数用来进行一般的绘图操作;option 参数为图形项提供了一个风格选项;widget 参数是可选的,如果提供了该参数,那么它会指向那个要在其上进行绘图的部件,否则默认为 0,表明使用缓冲绘图。painter 的画笔宽度默认为 0,它的画笔被初始化为绘图设备调色板的 QPalette::Text 画刷,而 painter 的画刷被初始化为 QPalette::Window。
示例实现:
void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{Q_UNUSED(option)Q_UNUSED(widget)painter->setBrush(Qt::red); // 设置填充颜色为红色painter->drawEllipse(-10, -10, 20, 20); // 绘制圆形
}
一定要保证所有绘图都在 boundingRect() 的边界之中。特别是当 QPainter 使用了指定的 QPen 来渲染图形的边界轮廓时,绘制的图形的边界线的一半会在外面,一半会在里面(例如,使用了宽度为两个单位的画笔,就必须在 boundingRect() 里绘制一个单位的边界线)。这也是在 boundingRect() 中要包含半个画笔宽度的原因。QGraphicsItem 不支持使用宽度非零的装饰笔。
1.3.2. 使用自定义图形项
在 main.cpp 文件中先添加头文件 #include "myitem.h",然后将以前的图形项的创建代码:
QGraphicsRectItem* item = new QGraphicsRectItem(0, 0, 100, 100);
更改为:
MyItem* item = new MyItem;
运行程序可以看到自定义的图形项(如红色小方块)出现在了视图的正中间,背景图片的位置也有所变化,这些问题会在后续的坐标系统中进行讲解。

通过上述步骤,即可实现自定义的图形项,满足在 Qt 图形视图框架中展示个性化图形元素的需求,为各种复杂图形界面应用开发提供基础。
如果只想添加简单的图形项,也可以直接使用图形视图框架提供的标准图形项,它们的效果如图所示。

在 Qt 中,QGraphicsItem 是图形视图框架中所有图形项的基类。以下是一些常见的标准图形项:
几何形状类
- QGraphicsEllipseItem :用于绘制椭圆或圆。可以通过设置矩形区域来确定椭圆的大小和位置,例如指定一个 QRectF 对象来定义椭圆的外接矩形。
- QGraphicsLineItem :用于绘制直线段。只需要指定直线段的起点和终点坐标即可创建。
- QGraphicsPathItem :用于绘制复杂的路径图形。可以使用 QPainterPath 来构建各种形状的路径,如多边形、曲线、折线等。
- QGraphicsPolygonItem :用于绘制多边形。可以通过提供一个 QPolygonF 对象来定义多边形的顶点坐标。
- QGraphicsRectItem :用于绘制矩形。可以通过指定矩形的左上角坐标、宽度和高度来创建,也可以通过设置一个 QRectF 对象来定义。
图像类
- QGraphicsPixmapItem :用于显示 pixmap 图像。可以加载图片文件并将其作为图形项显示在场景中。
- QGraphicsSimpleTextItem :用于显示简单的文本。可以设置文本内容、字体、颜色等属性。
- QGraphicsTextItem :功能更强大的文本图形项,支持富文本格式。不仅可以设置文本内容和基本属性,还可以设置段落格式、列表等。
其他类
- QGraphicsProxyWidget :可以在图形场景中嵌入一个 QWidget 及其子部件。可以将普通的窗口部件作为图形项来管理,使它们能够在图形视图中显示和交互。
- QGraphicsItemGroup :用于将多个图形项组合在一起,方便对这些图形项进行统一操作,如移动、旋转、缩放等。
最后
通过 QGraphicsScene、QGraphicsView 和 QGraphicsItem 三者的紧密协作,Qt 图形视图框架能够高效地处理大量图形项的显示、交互和管理操作,广泛应用于图形编辑器、游戏开发、数据可视化等领域。