Qt 图形视图框架功能详解QGraphicsScene、QGraphicsView 和 QGraphicsItem
  • 1. Qt 图形视图框架功能详解
    • 1.1. QGraphicsScene(场景)
    • 1.2. QGraphicsView(视图)
    • 1.3. QGraphicsItem(图形项)
      • 1.3.1. 关键函数实现
      • 1.3.2. 使用自定义图形项

1. Qt 图形视图框架功能详解

在 Qt 中,图形视图框架主要由 QGraphicsSceneQGraphicsViewQGraphicsItem 三大核心类构成,具有丰富功能。

1.1. QGraphicsScene(场景)

  1. 图形项管理

    • 作为图形项的容器,负责存储和管理各种 QGraphicsItem 及其派生类对象,如图形、文本、图片等。例如,可以将多个矩形、线条等图形项添加到场景中进行统一管理。
    • 提供对图形项的增删改查操作,方便动态调整场景中的内容。
  2. 事件处理

    • 是图形视图框架的事件中心,负责处理场景内图形项的各种事件,像鼠标点击、键盘操作、拖拽等事件。例如,当用户在场景中的某个图形项上点击鼠标时,场景会将该事件传递给对应的图形项进行处理。
    • 支持自定义事件过滤器,可用于对场景内事件进行统一管理和预处理。
  3. 高级功能支持

    • 支持拖拽操作,可实现图形项在场景内的拖动以及与其他应用间的拖放交互。
    • 配合动画框架,可为场景中的图形项创建动画效果,如平移、旋转、缩放等动画。
    • 支持与状态机框架结合,可根据不同状态对场景中的图形项进行相应控制。

看一个简单的例子:
新建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(视图)

  1. 场景显示

    • 用于显示 QGraphicsScene 场景中的内容,将场景中的图形项以可视化的方式呈现在窗口上。一个场景可以关联多个视图,不同视图可从不同角度或以不同方式显示同一场景。
    • 支持视口的滚动,当场景内容超出视口范围时,可通过滚动条查看完整内容。
  2. 交互功能

    • 提供视图的缩放功能,允许用户通过鼠标滚轮或调用相关接口对视图进行放大缩小操作,方便查看场景中的细节或整体布局。
    • 支持视图的平移,用户可通过拖拽视图或调用相应接口实现视图在场景上的移动,聚焦于感兴趣区域。
    • 具备可选择的拖拽模式,如无拖拽、手型拖拽和滚动手型拖拽等模式,满足不同交互需求。

我们继续看上面的例子,在主函数中 "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(图形项)

  1. 基本功能

    • 作为所有图形项的基类,定义了图形项的基本接口和属性,如位置、大小、变换(平移、旋转、缩放)、可见性等。
    • 支持绘制操作,可通过重写 paint() 函数自定义图形项的绘制方式,实现各种复杂形状和效果的图形显示。
    • 鼠标按下、移动、释放、双击、悬停、滚轮和右键菜单事件。
    • 键盘输入焦点和键盘事件。
    • 拖放事件。
    • 分组,使用QGraphicsItemGroup通过parent-child关系来实现。
    • 碰撞检测。
    • 除此之外,图形项还可以存储自定义的数据,可以使用setData()进行数据存储,然后使用data()获取其中的数据。
  2. 事件处理

    • 拥有丰富的事件处理机制,可处理鼠标事件(如按下、释放、双击等)、键盘事件、轮播事件、拖进拖出事件等。例如,在图形项上实现鼠标悬停时改变形状或颜色的效果。
    • 提供事件传播机制,事件可在图形项及其父项之间传递,便于实现复杂的交互逻辑。
  3. 图形项管理

    • 支持图形项的分层管理,可通过设置父项来建立图形项之间的层级关系,子项会随父项一起进行变换操作,如平移、旋转等。
    • 具备碰撞检测功能,可检测与其他图形项或形状之间的碰撞关系,为实现游戏、绘图等应用中的交互提供基础。

在 Qt 中,除了使用现成的图形项外,还支持自定义图形项以满足特定需求。我们在接着看上面的例子,这次要增加一个类:

  1. 创建类

在 Qt Creator 中为项目添加新文件,选择 “C++ 类” 模板,命名为 MyItem,基类设为 QGraphicsItem

  1. 修改头文件

对 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
  1. 实现文件修改

在 myitem.cpp 文件中添加头文件 #include <QPainter>,并定义添加的两个函数。

1.3.1. 关键函数实现

  1. boundingRect() 函数

该函数用于返回要绘制图形项的矩形区域,定义图形项的外部边界矩形。例如:

QRectF MyItem::boundingRect() const
{return QRectF(-10, -10, 20, 20); // 设置边界矩形,可根据实际图形调整
}

所有的绘图操作都必须限制在图形项的边界矩形之中。而且,QGraphicsView 要使用这个矩形来剔除那些不可见的图形项,还要使用它来确定绘制交叉项目时哪些区域需要进行重新构建。另外,QGraphicsItem 的碰撞检测机制也需要使用到这个边界矩形。如果图形绘制了一个轮廓,那么在边界矩形中包含一半画笔的宽度是很重要的,尽管对于抗锯齿绘图并不需要这些补偿。

  1. 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 :用于将多个图形项组合在一起,方便对这些图形项进行统一操作,如移动、旋转、缩放等。

最后

通过 QGraphicsSceneQGraphicsViewQGraphicsItem 三者的紧密协作,Qt 图形视图框架能够高效地处理大量图形项的显示、交互和管理操作,广泛应用于图形编辑器、游戏开发、数据可视化等领域。