绘图
绘图系统
Qt的二维绘图功能
- 主要使用QPainter进行绘图。
- 绘图设备包括QWidget、QPixmap、QPrinter等。
QWidget作为最常见的绘图设备
- QWidget是所有界面组件的基础。
- 界面组件的显示效果是通过QPainter在QWidget上实现。
- QPainter可以在QWidget上绘制自定义组件形状和实现特定显示效果,这是设计自定义界面组件的基础。
Qt的图形/视图架构
- 通过使用QGraphicsView、QGraphicsScene和各种QGraphicsItem类来构建一个图形场景。
- 可以在一个场景中绘制大量的图形项。
- 每个图形项都是可选择、可交互操作的。
QPainter绘图系统
QPainter 是 Qt 框架中的一个类,用于在各种绘图设备上绘制基本图形。
- 可以用于组件的显示效果,并支持绘制点、直线、圆、矩形、文字和位图,可以组合成复杂的图形。
绘图设备
QPaintDevice
- 所有绘图设备的基类,无父类。
QWidget
- 所有界面组件的基类,最常见的绘图设备类。
- 继承自 QPaintDevice 和 QObject,支持 Qt 的元对象系统。
图片相关类
QImage:
- 与硬件无关,用于设备输入输出。
- 支持直接访问和操作图片像素数据。
QPixmap:
- 为屏幕显示图片优化。
QBitmap:
- QPixmap 的子类,用于表示单色位图。
QPicture:
- 记录和回放 QPainter 指令。
矢量图形与渲染
QSvgGenerator:
- 创建 SVG 图形。
- 可以将绘图内容保存为 SVG 文件。
QSvgWidget:
- 显示 SVG 图片文件的组件类。
QOpenGLPaintDevice:
- 使用 OpenGL 渲染 QPainter 绘图指令。
- 需要系统支持 OpenGL 2.0 以上版本。
打印与文件输出
QPagedPaintDevice:
- 支持多个页面,适用于打印输出和 PDF 文件生成。
QPrinter:
- 用于打印输出,在设备上绘图以生成打印页面。
QPdfWriter:
- 生成 PDF 文件的设备类。
- 与 QPrinter 配合使用可保存为 PDF 文件。
QWidget绘图事件和绘图区
QWidget类有一个事件处理函数paintEvent(),在组件界面需要重绘时,系统会自动运行这个函数。
要在界面上绘图,我们需要在此事件处理函数里创建一个QPainter对象来获取绘图设备的接口,然后用这个QPainter对象在绘图设备上绘图。在事件处理函数paintEvent()里绘图的基本程
QGraphicsView
QPainter绘图的特性控制
- QPen
- QBrush
- QPainter
QPen
QBrush
QPainter
// 自定义仪表盘控件classSpeedometer:publicQWidget{protected:voidpaintEvent(QPaintEvent*)override{QPainterpainter(this);painter.setRenderHint(QPainter::Antialiasing);// 抗锯齿// 1. 绘制背景圆盘painter.setBrush(Qt::black);painter.drawEllipse(10,10,width()-20,height()-20);// 2. 绘制刻度)painter.setPen(QPen(Qt::white,3));for(inti=0;i<4;++i){painter.drawLine(50+i*50,80,50+i*50,100);}// 3. 绘制指针painter.save();// 保存状态painter.translate(width()/2,height()/2);// 移动到中心painter.rotate(80);// 根据车速旋转角度painter.setPen(QPen(Qt::red,4));painter.drawLine(0,0,60,0);// 画指针painter.restore();// 恢复状态}};坐标系统和坐标变换
QPainter在绘图设备上绘图时默认使用设备的物理坐标。
QPainter提供了一些接口函数可以进行平移、旋转、缩放等坐标变换,还可以在绘图设备上定义视口坐标和窗口坐标。
窗口坐标是逻辑坐标,使用QPainter在逻辑坐标系中绘图,可以自动适应绘图区大小的变化。
坐标系统
坐标系统扮演着核心角色,使得图形绘制变得灵活和有效。下面是Qt绘图中的坐标系统的主要概念:
坐标系概述
- 物理坐标系:指的是绘图设备的像素级坐标,通常与设备的实际分辨率相对应。
- 逻辑坐标系:一个抽象的坐标系统,用于在更高层次上进行绘图,允许根据需求自动适应不同的绘图区大小。
坐标转换
Qt提供了一些坐标转换功能,主要包括:
- 平移:可以通过translate()函数移动原点位置。
- 缩放:通过scale()函数调整绘图的大小,改变坐标的比例。
- 旋转:使用rotate()函数可以围绕原点旋转坐标系,使得图形相应旋转。
QPainter提供了一些坐标变换功能
| 函数名 | 功能描述 |
|---|---|
| translate(qreal dx, qreal dy) | 平移图形或坐标轴。 |
| rotate(qreal angle) | 旋转图形或坐标轴。 |
| scale(qreal sx, qreal sy) | 缩放图形或坐标轴。 |
| shear(qreal sh, qreal sv) | 对图形进行斜切变换。 |
| save() | 保存当前的图形状态(包括变换矩阵等)。常用于变换操作之前保存原始状态,以便之后恢复。 |
| restore() | 恢复之前保存的图形状态。常与save()配合使用,用于撤销之前的变换操作。 |
| resetTransform() | 重置图形状态到默认状态(通常是初始状态,无变换)。 |
视口和窗口
- 视口(Viewport):指当前绘图设备的显示区域。可以通过setViewport()定义。
- 窗口(Window):逻辑坐标系中的一个区域,通过setWindow()定义。逻辑坐标将在这个窗口内进行绘制。
逻辑坐标绘图
- 使用逻辑坐标绘图时,可以实现自动适应绘图区大小的特性,使得图形能够在不同的窗口大小下保持比例和位置。
QPainter的使用
- 在 QPainter 对象上,通常可以通过以下步骤设置坐标系统:
- 创建QPainter对象。
- 设置视口和窗口坐标。
- 进行绘图操作。
视口和窗口
视口和窗口的定义
绘图设备的物理坐标系是基本的坐标系,通过QPainter 的平移、旋转等坐标变换可以得到更容易操作的逻辑坐标系。
物理坐标系也称为视口(viewport)坐标系,逻辑坐标系也称为窗口( window)坐标系,通过内部的坐标变换矩阵,
QPainter 能自动将逻辑坐标变换为绘图设备的物理坐标。
图形/视图架构
一、QPainter绘图方法
- 概述:
- QPainter是Qt中用于绘图的核心类,它提供了一套丰富的绘图API。
- 使用QPainter绘图时,通常需要在绘图设备(如QWidget或QGraphicsView等)的事件处理函数paintEvent()中编写绘图代码。
- 通过QPainter绘制的图形是位图,即图像由像素点组成,放大或缩小时可能会失真。
- 使用场景:
- 适用于简单的图形绘制,如绘制线条、矩形、圆形等基础图形。
- 适用于需要快速绘制且对图形质量要求不高的情况。
二、图形/视图架构
- 概述:
- Qt提供了图形/视图(graphics/view)架构,这是一种基于图形项(graphics item)的模型/视图结构。
- 图形/视图架构允许开发者绘制复杂的图形,这些图形由成千上万个基本图形组件组成,并且每个图形组件都是可选择、可拖放和可修改的。
- 与QPainter绘图不同,图形/视图架构绘制的图形是矢量图,即图形由几何形状和颜色等属性描述,放大或缩小时不会失真。
- 核心组件:图形/视图架构主要由3个部分组成:
- 图形项(Graphics Item):代表图形的基本组件,如线条、矩形、圆形等。每个图形项都是独立的,可以拥有自己的属性(如位置、大小、颜色等)和行为(如响应鼠标事件、动画等)。
- 视图(View):用于显示图形项的场景。视图可以嵌入到QWidget中,作为用户界面的一部分。
- 场景(Scene):作为图形项的容器,管理所有图形项的位置、大小、可见性等属性。场景可以包含多个图形项,并且支持图形项的添加、删除、移动等操作。
- 使用场景:
- 适用于需要绘制复杂图形且图形组件需要交互的情况,如矢量绘图软件、图形编辑器、游戏界面等。
- 允许用户通过拖放、选择、修改等操作与图形进行交互,提高用户体验。
图形/视图架构的坐标系
在Qt的图形/视图架构中,坐标系的使用是设计和实现交互式图形界面的核心。以下是这套架构的主要坐标系介绍:
场景坐标系(Scene Coordinates)
- 定义:场景坐标系是整个QGraphicsScene使用的坐标系统。
- 特点:所有添加到场景中的项(QGraphicsItem)都以此坐标系进行定位。场景坐标是绝对的,可以用来准确表示图形项的位置和大小。
视口坐标系(Viewport Coordinates)
- 定义:视口坐标系对应于QGraphicsView的可视区域。
- 特点:视口坐标是相对的,局限于QGraphicsView的显示区域。它可以通过平移和缩放与场景坐标系进行转换。
- 使用:在视口坐标系中,用户交互(例如鼠标事件)和绘制都是基于这个坐标系统进行的。
逻辑坐标系(Logical Coordinates)
- 定义:是用于在场景中绘图的逻辑坐标。用户可以在这个坐标系中设计和布局图形项,而不必关心其在具体视口中的表现。
- 特点:逻辑坐标可以随着视图的缩放和移动进行调整,这使得图形项能够在不同显示条件下保持相对位置。
坐标变换
- 平移:可以通过QGraphicsView的变换功能来移动场景的视图,影响视口坐标系中的项的位置。
- 缩放:视口也支持缩放操作,通过scale()函数,可以改变视口显示内容的比例,而场景的逻辑坐标仍保持不变。
- 旋转:视图也支持旋转变换,这会影响视口中的项的显示角度。
转换关系
- Qt提供了一系列函数,例如mapToScene()和mapFromScene(),用于在视口坐标和场景坐标之间转换。这使得事件处理和绘图操作能够有效地在不同坐标系之间切换。
图像处理
QImage和 QPixmap是用于图像显示和处理的绘图设备类。
图片基础
一、颜色数据格式
- 概述:
- 图像的显示基于每个像素的颜色数据。
- 颜色数据有多种表示格式,常见的有RGB32、RGB888、ARGB32、RGBA32、RGB565和灰度等。
- 具体格式说明:
- RGB32:使用32位无符号整数表示,实际用24位有效数据表示颜色,常用于计算机上存储的图片文件。
- RGB888:红色、绿色、蓝色各用1字节表示,共占3字节,但非标准整数类型,常在内存有限的系统中使用。
- ARGB32和RGBA32:在RGB基础上加入Alpha值表示不透明度。
- RGB565:用16位无符号整数表示,适用于嵌入式设备的TFT-LCD,可节省存储空间。
- Grayscale8和Grayscale16:用于表示灰度颜色的8位和16位无符号整数。
二、图片文件格式
- BMP格式:
- 位图文件格式,存储图像的宽度、高度、颜色数据等。
- 像素颜色数据无修改地保存在文件中,如RGB32数据。
- BMP是无损图片文件格式,文件较大。
- JPG格式:
- 使用JPEG压缩算法的有损压缩格式。
- 可减小文件大小,节省存储空间,但有一定图像质量损失。
- BMP图片文件转换为JPG后,JPG文件大小通常只有BMP的约10%。
- PNG格式:
- 无损压缩图片文件格式,具有一定压缩率。
- 文件解压后为真实原图,支持Alpha通道,如ARGB32颜色数据。
- SVG格式:
- 基于XML的矢量图文件格式,不存储像素颜色数据,而是描述图像绘制方法。
- 不能用QImage和QPixmap类处理,需使用QSvgRenderer和QSvgWidget类读取和显示。
QImage
QImage 是 Qt 图形模块中的一个类,主要用于处理和存储图像数据。它提供了多种功能,包括图像加载、保存、绘制和操作,是 Qt 图形应用中的重要组件。
主要特性
- 多种格式支持:
- 支持多种图像格式,如 PNG、JPEG、BMP 等。
- 图像操作:
- 提供丰富的图像处理功能,如缩放、旋转、裁剪、颜色转换等。
- 直接访问像素:
- 可直接操作图像的像素数据,支持高效的图像处理。
- 与 QPainter 兼容:
- 可以与 QPainter 类结合使用,将图像绘制到窗口或其他图形设备上。
常用方法
- 加载和保存图像:
QImage image;image.load("image.png");image.save("output.jpg");- 访问像素:
QRgb pixel=image.pixel(x,y);// 获取像素颜色image.setPixel(x,y,qRgb(255,0,0));// 设置像素颜色为红色- 图像转换:
QImage scaledImage=image.scaled(100,100,Qt::KeepAspectRatio);- 绘制图像:
QPainterpainter(this);painter.drawImage(0,0,image);示例:如何使用 QImage 加载、处理和绘制图像。
#include<QApplication>#include<QWidget>#include<QImage>#include<QPainter>classImageWidget:publicQWidget{protected:voidpaintEvent(QPaintEvent*)override{QImageimage("example.png");// 加载图像if(!image.isNull()){QPainterpainter(this);painter.drawImage(0,0,image.scaled(size(),Qt::KeepAspectRatio));// 绘制缩放后的图像}}};intmain(intargc,char*argv[]){QApplicationapp(argc,argv);ImageWidget w;w.resize(800,600);w.setWindowTitle("QImage Example");w.show();returnapp.exec();}